"Fossies" - the Fresh Open Source Software Archive

Member "ndiswrapper-1.63/driver/wrapndis.c" (3 May 2020, 66476 Bytes) of package /linux/misc/ndiswrapper-1.63.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "wrapndis.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.62_vs_1.63.

    1 /*
    2  *  Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
    3  *
    4  *  This program is free software; you can redistribute it and/or modify
    5  *  it under the terms of the GNU General Public License as published by
    6  *  the Free Software Foundation; either version 2 of the License, or
    7  *  (at your option) any later version.
    8  *
    9  *  This program is distributed in the hope that it will be useful,
   10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   12  *  GNU General Public License for more details.
   13  *
   14  */
   15 
   16 #include <linux/inetdevice.h>
   17 #include <linux/ip.h>
   18 #include <linux/in.h>
   19 #include <linux/proc_fs.h>
   20 #include "ndis.h"
   21 #include "iw_ndis.h"
   22 #include "pnp.h"
   23 #include "loader.h"
   24 #include "wrapndis.h"
   25 #include "wrapper.h"
   26 
   27 /* Functions callable from the NDIS driver */
   28 wstdcall NTSTATUS NdisDispatchDeviceControl(struct device_object *fdo,
   29                         struct irp *irp);
   30 wstdcall NTSTATUS NdisDispatchPnp(struct device_object *fdo, struct irp *irp);
   31 wstdcall NTSTATUS NdisDispatchPower(struct device_object *fdo, struct irp *irp);
   32 
   33 struct workqueue_struct *wrapndis_wq;
   34 
   35 static int set_packet_filter(struct ndis_device *wnd,
   36                  ULONG packet_filter);
   37 static void add_iw_stats_timer(struct ndis_device *wnd);
   38 static void del_iw_stats_timer(struct ndis_device *wnd);
   39 static NDIS_STATUS ndis_start_device(struct ndis_device *wnd);
   40 static int ndis_remove_device(struct ndis_device *wnd);
   41 static void set_multicast_list(struct ndis_device *wnd);
   42 static int ndis_net_dev_open(struct net_device *net_dev);
   43 static int ndis_net_dev_close(struct net_device *net_dev);
   44 
   45 /* MiniportReset */
   46 NDIS_STATUS mp_reset(struct ndis_device *wnd)
   47 {
   48     NDIS_STATUS res;
   49     struct miniport *mp;
   50     BOOLEAN reset_address;
   51     KIRQL irql;
   52 
   53     ENTER2("wnd: %p", wnd);
   54     mutex_lock(&wnd->tx_ring_mutex);
   55     mutex_lock(&wnd->ndis_req_mutex);
   56     mp = &wnd->wd->driver->ndis_driver->mp;
   57     prepare_wait_condition(wnd->ndis_req_task, wnd->ndis_req_done, 0);
   58     WARNING("%s is being reset", wnd->net_dev->name);
   59     irql = serialize_lock_irql(wnd);
   60     assert_irql(_irql_ == DISPATCH_LEVEL);
   61     res = LIN2WIN2(mp->reset, &reset_address, wnd->nmb->mp_ctx);
   62     serialize_unlock_irql(wnd, irql);
   63 
   64     TRACE2("%08X, %08X", res, reset_address);
   65     if (res == NDIS_STATUS_PENDING) {
   66         /* wait for NdisMResetComplete */
   67         if (wait_condition((wnd->ndis_req_done > 0), 0,
   68                    TASK_INTERRUPTIBLE) < 0)
   69             res = NDIS_STATUS_FAILURE;
   70         else {
   71             res = wnd->ndis_req_status;
   72             reset_address = wnd->ndis_req_done - 1;
   73         }
   74         TRACE2("%08X, %08X", res, reset_address);
   75     }
   76     mutex_unlock(&wnd->ndis_req_mutex);
   77     if (res == NDIS_STATUS_SUCCESS && reset_address) {
   78         set_packet_filter(wnd, wnd->packet_filter);
   79         set_multicast_list(wnd);
   80     }
   81     mutex_unlock(&wnd->tx_ring_mutex);
   82     EXIT3(return res);
   83 }
   84 
   85 /* MiniportRequest(Query/Set)Information */
   86 NDIS_STATUS mp_request(enum ndis_request_type request,
   87                struct ndis_device *wnd, ndis_oid oid,
   88                void *buf, ULONG buflen, ULONG *written, ULONG *needed)
   89 {
   90     NDIS_STATUS res;
   91     ULONG w, n;
   92     struct miniport *mp;
   93     KIRQL irql;
   94 
   95     mutex_lock(&wnd->ndis_req_mutex);
   96     if (!written)
   97         written = &w;
   98     if (!needed)
   99         needed = &n;
  100     mp = &wnd->wd->driver->ndis_driver->mp;
  101     prepare_wait_condition(wnd->ndis_req_task, wnd->ndis_req_done, 0);
  102     irql = serialize_lock_irql(wnd);
  103     assert_irql(_irql_ == DISPATCH_LEVEL);
  104     switch (request) {
  105     case NdisRequestQueryInformation:
  106         TRACE2("%p, %08X, %p", mp->queryinfo, oid, wnd->nmb->mp_ctx);
  107         res = LIN2WIN6(mp->queryinfo, wnd->nmb->mp_ctx, oid, buf,
  108                    buflen, written, needed);
  109         break;
  110     case NdisRequestSetInformation:
  111         TRACE2("%p, %08X, %p", mp->setinfo, oid, wnd->nmb->mp_ctx);
  112         res = LIN2WIN6(mp->setinfo, wnd->nmb->mp_ctx, oid, buf,
  113                    buflen, written, needed);
  114         break;
  115     default:
  116         WARNING("invalid request %d, %08X", request, oid);
  117         res = NDIS_STATUS_NOT_SUPPORTED;
  118         break;
  119     }
  120     serialize_unlock_irql(wnd, irql);
  121     TRACE2("%08X, %08X", res, oid);
  122     if (res == NDIS_STATUS_PENDING) {
  123         /* wait for NdisMQueryInformationComplete */
  124         if (wait_condition((wnd->ndis_req_done > 0), 0,
  125                    TASK_INTERRUPTIBLE) < 0)
  126             res = NDIS_STATUS_FAILURE;
  127         else
  128             res = wnd->ndis_req_status;
  129         TRACE2("%08X, %08X", res, oid);
  130     }
  131     mutex_unlock(&wnd->ndis_req_mutex);
  132     DBG_BLOCK(2) {
  133         if (res || needed)
  134             TRACE2("%08X, %d, %d, %d", res, buflen, *written,
  135                    *needed);
  136     }
  137     EXIT3(return res);
  138 }
  139 
  140 /* MiniportPnPEventNotify */
  141 static NDIS_STATUS mp_pnp_event(struct ndis_device *wnd,
  142                 enum ndis_device_pnp_event event,
  143                 ULONG power_profile)
  144 {
  145     struct miniport *mp;
  146 
  147     ENTER1("%p, %d", wnd, event);
  148     mp = &wnd->wd->driver->ndis_driver->mp;
  149     if (!mp->pnp_event_notify) {
  150         TRACE1("Windows driver %s doesn't support "
  151                "MiniportPnpEventNotify", wnd->wd->driver->name);
  152         return NDIS_STATUS_FAILURE;
  153     }
  154     /* RNDIS driver doesn't like to be notified if device is
  155      * already halted */
  156     if (!test_bit(HW_INITIALIZED, &wnd->wd->hw_status))
  157         EXIT1(return NDIS_STATUS_SUCCESS);
  158     switch (event) {
  159     case NdisDevicePnPEventSurpriseRemoved:
  160         TRACE1("%u, %p",
  161                (wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK),
  162                mp->pnp_event_notify);
  163         if ((wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK) &&
  164             !test_bit(HW_DISABLED, &wnd->wd->hw_status) &&
  165             mp->pnp_event_notify) {
  166             TRACE1("calling surprise_removed");
  167             LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx,
  168                  NdisDevicePnPEventSurpriseRemoved, NULL, 0);
  169         } else
  170             TRACE1("Windows driver %s doesn't support "
  171                    "MiniportPnpEventNotify for safe unplugging",
  172                    wnd->wd->driver->name);
  173         return NDIS_STATUS_SUCCESS;
  174     case NdisDevicePnPEventPowerProfileChanged:
  175         if (power_profile)
  176             power_profile = NdisPowerProfileAcOnLine;
  177         LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx,
  178              NdisDevicePnPEventPowerProfileChanged,
  179              &power_profile, sizeof(power_profile));
  180         return NDIS_STATUS_SUCCESS;
  181     default:
  182         WARNING("event %d not yet implemented", event);
  183         return NDIS_STATUS_SUCCESS;
  184     }
  185 }
  186 
  187 /* MiniportInitialize */
  188 static NDIS_STATUS mp_init(struct ndis_device *wnd)
  189 {
  190     NDIS_STATUS error_status, status;
  191     UINT medium_index;
  192     enum ndis_medium medium_array[] = {NdisMedium802_3};
  193     struct miniport *mp;
  194 
  195     ENTER1("irql: %d", current_irql());
  196     if (test_bit(HW_INITIALIZED, &wnd->wd->hw_status)) {
  197         WARNING("device %p already initialized!", wnd);
  198         return NDIS_STATUS_FAILURE;
  199     }
  200 
  201     if (!wnd->wd->driver->ndis_driver ||
  202         !wnd->wd->driver->ndis_driver->mp.init) {
  203         WARNING("assuming WDM (non-NDIS) driver");
  204         EXIT1(return NDIS_STATUS_NOT_RECOGNIZED);
  205     }
  206     mp = &wnd->wd->driver->ndis_driver->mp;
  207     status = LIN2WIN6(mp->init, &error_status, &medium_index, medium_array,
  208               ARRAY_SIZE(medium_array), wnd->nmb, wnd->nmb);
  209     TRACE1("init returns: %08X, irql: %d", status, current_irql());
  210     if (status != NDIS_STATUS_SUCCESS) {
  211         WARNING("couldn't initialize device: %08X", status);
  212         EXIT1(return NDIS_STATUS_FAILURE);
  213     }
  214 
  215     /* Wait a little to let card power up otherwise ifup might
  216      * fail after boot */
  217     sleep_hz(HZ / 5);
  218     status = mp_pnp_event(wnd, NdisDevicePnPEventPowerProfileChanged,
  219                   NdisPowerProfileAcOnLine);
  220     if (status != NDIS_STATUS_SUCCESS)
  221         TRACE1("setting power failed: %08X", status);
  222     set_bit(HW_INITIALIZED, &wnd->wd->hw_status);
  223     /* the description about NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND is
  224      * misleading/confusing */
  225     status = mp_query(wnd, OID_PNP_CAPABILITIES,
  226               &wnd->pnp_capa, sizeof(wnd->pnp_capa));
  227     if (status == NDIS_STATUS_SUCCESS) {
  228         TRACE1("%d, %d", wnd->pnp_capa.wakeup.min_magic_packet_wakeup,
  229                wnd->pnp_capa.wakeup.min_pattern_wakeup);
  230         wnd->attributes |= NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;
  231         status = mp_query_int(wnd, OID_PNP_ENABLE_WAKE_UP,
  232                       &wnd->ndis_wolopts);
  233         TRACE1("%08X, %x", status, wnd->ndis_wolopts);
  234     } else if (status == NDIS_STATUS_NOT_SUPPORTED)
  235         wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;
  236     TRACE1("%d", wnd->pnp_capa.wakeup.min_magic_packet_wakeup);
  237     /* although some NDIS drivers support suspend, Linux kernel
  238      * has issues with suspending USB devices */
  239     if (wrap_is_usb_bus(wnd->wd->dev_bus)) {
  240         wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;
  241         wnd->ndis_wolopts = 0;
  242     }
  243     mp_set_int(wnd, OID_802_11_POWER_MODE, NDIS_POWER_OFF);
  244     EXIT1(return NDIS_STATUS_SUCCESS);
  245 }
  246 
  247 /* MiniportHalt */
  248 static void mp_halt(struct ndis_device *wnd)
  249 {
  250     struct miniport *mp;
  251 
  252     ENTER1("%p", wnd);
  253     if (!test_and_clear_bit(HW_INITIALIZED, &wnd->wd->hw_status)) {
  254         WARNING("device %p is not initialized - not halting", wnd);
  255         return;
  256     }
  257     hangcheck_del(wnd);
  258     del_iw_stats_timer(wnd);
  259 #ifdef CONFIG_WIRELESS_EXT
  260     if (wnd->physical_medium == NdisPhysicalMediumWirelessLan &&
  261         wrap_is_pci_bus(wnd->wd->dev_bus)) {
  262         mutex_unlock(&wnd->ndis_req_mutex);
  263         disassociate(wnd, 0);
  264         mutex_lock(&wnd->ndis_req_mutex);
  265     }
  266 #endif
  267     mp = &wnd->wd->driver->ndis_driver->mp;
  268     TRACE1("halt: %p", mp->mp_halt);
  269     LIN2WIN1(mp->mp_halt, wnd->nmb->mp_ctx);
  270     /* if a driver doesn't call NdisMDeregisterInterrupt during
  271      * halt, deregister it now */
  272     if (wnd->mp_interrupt)
  273         NdisMDeregisterInterrupt(wnd->mp_interrupt);
  274     /* cancel any timers left by buggy windows driver; also free
  275      * the memory for timers */
  276     while (1) {
  277         struct nt_slist *slist;
  278         struct wrap_timer *wrap_timer;
  279 
  280         spin_lock_bh(&ntoskernel_lock);
  281         if ((slist = wnd->wrap_timer_slist.next))
  282             wnd->wrap_timer_slist.next = slist->next;
  283         spin_unlock_bh(&ntoskernel_lock);
  284         TIMERTRACE("%p", slist);
  285         if (!slist)
  286             break;
  287         wrap_timer = container_of(slist, struct wrap_timer, slist);
  288         wrap_timer->repeat = 0;
  289         /* ktimer that this wrap_timer is associated to can't
  290          * be touched, as it may have been freed by the driver
  291          * already */
  292         if (del_timer_sync(&wrap_timer->timer))
  293             WARNING("Buggy Windows driver left timer %p "
  294                 "running", wrap_timer->nt_timer);
  295         memset(wrap_timer, 0, sizeof(*wrap_timer));
  296         kfree(wrap_timer);
  297     }
  298     EXIT1(return);
  299 }
  300 
  301 static NDIS_STATUS mp_set_power_state(struct ndis_device *wnd,
  302                       enum ndis_power_state state)
  303 {
  304     NDIS_STATUS status;
  305 
  306     TRACE1("%d", state);
  307     if (state == NdisDeviceStateD0) {
  308         status = NDIS_STATUS_SUCCESS;
  309         mutex_unlock(&wnd->ndis_req_mutex);
  310         if (test_and_clear_bit(HW_HALTED, &wnd->wd->hw_status)) {
  311             status = mp_init(wnd);
  312             if (status == NDIS_STATUS_SUCCESS) {
  313                 set_packet_filter(wnd, wnd->packet_filter);
  314                 set_multicast_list(wnd);
  315             }
  316         } else if (test_and_clear_bit(HW_SUSPENDED,
  317                           &wnd->wd->hw_status)) {
  318             status = mp_set_int(wnd, OID_PNP_SET_POWER, state);
  319             if (status != NDIS_STATUS_SUCCESS)
  320                 WARNING("%s: setting power to state %d failed? "
  321                     "%08X", wnd->net_dev->name, state,
  322                     status);
  323         } else
  324             return NDIS_STATUS_FAILURE;
  325 
  326         if (wrap_is_pci_bus(wnd->wd->dev_bus)) {
  327             pci_enable_wake(wnd->wd->pci.pdev, PCI_D3hot, 0);
  328             pci_enable_wake(wnd->wd->pci.pdev, PCI_D3cold, 0);
  329         }
  330         if (status == NDIS_STATUS_SUCCESS) {
  331             mutex_unlock(&wnd->tx_ring_mutex);
  332             netif_device_attach(wnd->net_dev);
  333             hangcheck_add(wnd);
  334             add_iw_stats_timer(wnd);
  335         } else
  336             WARNING("%s: couldn't set power to state %d; device not"
  337                 " resumed", wnd->net_dev->name, state);
  338         EXIT1(return status);
  339     } else {
  340         mutex_lock(&wnd->tx_ring_mutex);
  341         netif_device_detach(wnd->net_dev);
  342         hangcheck_del(wnd);
  343         del_iw_stats_timer(wnd);
  344         status = NDIS_STATUS_NOT_SUPPORTED;
  345         if (wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND) {
  346             status = mp_set_int(wnd, OID_PNP_ENABLE_WAKE_UP,
  347                         wnd->ndis_wolopts);
  348             TRACE2("0x%x, 0x%x", status, wnd->ndis_wolopts);
  349             if (status == NDIS_STATUS_SUCCESS &&
  350                 wrap_is_pci_bus(wnd->wd->dev_bus)) {
  351                 if (wnd->ndis_wolopts)
  352                     wnd->wd->pci.wake_state =
  353                         PowerDeviceD3;
  354                 else
  355                     wnd->wd->pci.wake_state =
  356                         PowerDeviceUnspecified;
  357             } else
  358                 WARNING("couldn't set wake-on-lan options: "
  359                     "0x%x, %08X", wnd->ndis_wolopts, status);
  360             status = mp_set_int(wnd, OID_PNP_SET_POWER, state);
  361             if (status == NDIS_STATUS_SUCCESS)
  362                 set_bit(HW_SUSPENDED, &wnd->wd->hw_status);
  363             else
  364                 WARNING("suspend failed: %08X", status);
  365         }
  366         if (status != NDIS_STATUS_SUCCESS) {
  367             WARNING("%s does not support power management; "
  368                 "halting the device", wnd->net_dev->name);
  369             mp_halt(wnd);
  370             set_bit(HW_HALTED, &wnd->wd->hw_status);
  371             status = STATUS_SUCCESS;
  372         }
  373         mutex_lock(&wnd->ndis_req_mutex);
  374         EXIT1(return status);
  375     }
  376 }
  377 
  378 static int ndis_set_mac_address(struct net_device *dev, void *p)
  379 {
  380     struct ndis_device *wnd = netdev_priv(dev);
  381     struct sockaddr *addr = p;
  382     struct ndis_configuration_parameter param;
  383     struct unicode_string key;
  384     struct ansi_string ansi;
  385     NDIS_STATUS res;
  386     unsigned char mac_string[2 * ETH_ALEN + 1];
  387     mac_address mac;
  388 
  389     memcpy(mac, addr->sa_data, sizeof(mac));
  390     memset(mac_string, 0, sizeof(mac_string));
  391     res = snprintf(mac_string, sizeof(mac_string), MACSTR, MAC2STR(mac));
  392     if (res != (sizeof(mac_string) - 1))
  393         EXIT1(return -EINVAL);
  394     TRACE1("new mac: %s", mac_string);
  395 
  396     RtlInitAnsiString(&ansi, mac_string);
  397     if (RtlAnsiStringToUnicodeString(&param.data.string, &ansi,
  398                      TRUE) != STATUS_SUCCESS)
  399         EXIT1(return -EINVAL);
  400 
  401     param.type = NdisParameterString;
  402     RtlInitAnsiString(&ansi, "NetworkAddress");
  403     if (RtlAnsiStringToUnicodeString(&key, &ansi, TRUE) != STATUS_SUCCESS) {
  404         RtlFreeUnicodeString(&param.data.string);
  405         EXIT1(return -EINVAL);
  406     }
  407     NdisWriteConfiguration(&res, wnd->nmb, &key, &param);
  408     RtlFreeUnicodeString(&key);
  409     RtlFreeUnicodeString(&param.data.string);
  410 
  411     if (res != NDIS_STATUS_SUCCESS)
  412         EXIT1(return -EFAULT);
  413     if (ndis_reinit(wnd) == NDIS_STATUS_SUCCESS) {
  414         res = mp_query(wnd, OID_802_3_CURRENT_ADDRESS,
  415                    mac, sizeof(mac));
  416         if (res == NDIS_STATUS_SUCCESS) {
  417             TRACE1("mac:" MACSTRSEP, MAC2STR(mac));
  418             memcpy(dev->dev_addr, mac, sizeof(mac));
  419         } else
  420             ERROR("couldn't get mac address: %08X", res);
  421     }
  422     EXIT1(return 0);
  423 }
  424 
  425 static int setup_tx_sg_list(struct ndis_device *wnd, struct sk_buff *skb,
  426                 struct ndis_packet_oob_data *oob_data)
  427 {
  428     struct ndis_sg_element *sg_element;
  429     struct ndis_sg_list *sg_list;
  430     int i;
  431 
  432     ENTER3("%p, %d", skb, skb_shinfo(skb)->nr_frags);
  433     if (skb_shinfo(skb)->nr_frags <= 1) {
  434         sg_element = &oob_data->wrap_tx_sg_list.elements[0];
  435         sg_element->address =
  436             PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, skb->data,
  437                        skb->len, PCI_DMA_TODEVICE);
  438         sg_element->length = skb->len;
  439         oob_data->wrap_tx_sg_list.nent = 1;
  440         oob_data->ext.info[ScatterGatherListPacketInfo] =
  441             &oob_data->wrap_tx_sg_list;
  442         TRACE3("%llx, %u", sg_element->address, sg_element->length);
  443         return 0;
  444     }
  445     sg_list = kmalloc(sizeof(*sg_list) +
  446               (skb_shinfo(skb)->nr_frags + 1) * sizeof(*sg_element),
  447               GFP_ATOMIC);
  448     if (!sg_list)
  449         return -ENOMEM;
  450     sg_list->nent = skb_shinfo(skb)->nr_frags + 1;
  451     TRACE3("%p, %d", sg_list, sg_list->nent);
  452     sg_element = sg_list->elements;
  453     sg_element->length = skb_headlen(skb);
  454     sg_element->address =
  455         PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, skb->data,
  456                    skb_headlen(skb), PCI_DMA_TODEVICE);
  457     for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
  458         skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
  459         sg_element++;
  460 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0)
  461         sg_element->length = skb_frag_size(frag);
  462 #else
  463         sg_element->length = frag->size;
  464 #endif
  465         sg_element->address =
  466             pci_map_page(wnd->wd->pci.pdev, skb_frag_page(frag),
  467 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0)
  468                      skb_frag_off(frag), skb_frag_size(frag),
  469 #else
  470                      frag->page_offset, frag->size,
  471 #endif
  472                      PCI_DMA_TODEVICE);
  473         TRACE3("%llx, %u", sg_element->address, sg_element->length);
  474     }
  475     oob_data->ext.info[ScatterGatherListPacketInfo] = sg_list;
  476     return 0;
  477 }
  478 
  479 static void free_tx_sg_list(struct ndis_device *wnd,
  480                 struct ndis_packet_oob_data *oob_data)
  481 {
  482     int i;
  483     struct ndis_sg_element *sg_element;
  484     struct ndis_sg_list *sg_list =
  485         oob_data->ext.info[ScatterGatherListPacketInfo];
  486     sg_element = sg_list->elements;
  487     TRACE3("%p, %d", sg_list, sg_list->nent);
  488     PCI_DMA_UNMAP_SINGLE(wnd->wd->pci.pdev, sg_element->address,
  489                  sg_element->length, PCI_DMA_TODEVICE);
  490     if (sg_list->nent == 1)
  491         EXIT3(return);
  492     for (i = 1; i < sg_list->nent; i++, sg_element++) {
  493         TRACE3("%llx, %u", sg_element->address, sg_element->length);
  494         pci_unmap_page(wnd->wd->pci.pdev, sg_element->address,
  495                    sg_element->length, PCI_DMA_TODEVICE);
  496     }
  497     TRACE3("%p", sg_list);
  498     kfree(sg_list);
  499 }
  500 
  501 static struct ndis_packet *alloc_tx_packet(struct ndis_device *wnd,
  502                        struct sk_buff *skb)
  503 {
  504     struct ndis_packet *packet;
  505     ndis_buffer *buffer;
  506     struct ndis_packet_oob_data *oob_data;
  507     NDIS_STATUS status;
  508 
  509     NdisAllocatePacket(&status, &packet, wnd->tx_packet_pool);
  510     if (status != NDIS_STATUS_SUCCESS)
  511         return NULL;
  512     NdisAllocateBuffer(&status, &buffer, wnd->tx_buffer_pool,
  513                skb->data, skb->len);
  514     if (status != NDIS_STATUS_SUCCESS) {
  515         NdisFreePacket(packet);
  516         return NULL;
  517     }
  518     packet->private.buffer_head = buffer;
  519     packet->private.buffer_tail = buffer;
  520 
  521     oob_data = NDIS_PACKET_OOB_DATA(packet);
  522     oob_data->tx_skb = skb;
  523     if (wnd->sg_dma_size) {
  524         if (setup_tx_sg_list(wnd, skb, oob_data)) {
  525             NdisFreeBuffer(buffer);
  526             NdisFreePacket(packet);
  527             return NULL;
  528         }
  529     }
  530     if (skb->ip_summed == CHECKSUM_PARTIAL) {
  531         struct ndis_tcp_ip_checksum_packet_info csum;
  532         int protocol;
  533 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21)
  534         protocol = ntohs(skb->protocol);
  535 #else
  536         protocol = skb->nh.iph->protocol;
  537 #endif
  538         csum.value = 0;
  539         csum.tx.v4 = 1;
  540         if (protocol == IPPROTO_TCP)
  541             csum.tx.tcp = 1;
  542         else if (protocol == IPPROTO_UDP)
  543             csum.tx.udp = 1;
  544 //      csum->tx.ip = 1;
  545         packet->private.flags |= NDIS_PROTOCOL_ID_TCP_IP;
  546         oob_data->ext.info[TcpIpChecksumPacketInfo] =
  547             (void *)(ULONG_PTR)csum.value;
  548     }
  549     DBG_BLOCK(4) {
  550         dump_bytes(__func__, skb->data, skb->len);
  551     }
  552     TRACE4("%p, %p, %p", packet, buffer, skb);
  553     return packet;
  554 }
  555 
  556 void free_tx_packet(struct ndis_device *wnd, struct ndis_packet *packet,
  557             NDIS_STATUS status)
  558 {
  559     ndis_buffer *buffer;
  560     struct ndis_packet_oob_data *oob_data;
  561     struct sk_buff *skb;
  562     struct ndis_packet_pool *pool;
  563 
  564     assert_irql(_irql_ <= DISPATCH_LEVEL);
  565     assert(packet->private.packet_flags);
  566     oob_data = NDIS_PACKET_OOB_DATA(packet);
  567     skb = oob_data->tx_skb;
  568     buffer = packet->private.buffer_head;
  569     TRACE4("%p, %p, %p, %08X", packet, buffer, skb, status);
  570     if (status == NDIS_STATUS_SUCCESS) {
  571         pre_atomic_add(wnd->net_stats.tx_bytes, packet->private.len);
  572         atomic_inc_var(wnd->net_stats.tx_packets);
  573     } else {
  574         TRACE1("packet dropped: %08X", status);
  575         atomic_inc_var(wnd->net_stats.tx_dropped);
  576     }
  577     if (wnd->sg_dma_size)
  578         free_tx_sg_list(wnd, oob_data);
  579     NdisFreeBuffer(buffer);
  580     dev_kfree_skb_any(skb);
  581     pool = packet->private.pool;
  582     NdisFreePacket(packet);
  583     if (netif_queue_stopped(wnd->net_dev) &&
  584         ((pool->max_descr - pool->num_used_descr) >=
  585          (wnd->max_tx_packets / 4))) {
  586         set_bit(NETIF_WAKEQ, &wnd->ndis_pending_work);
  587         queue_work(wrapndis_wq, &wnd->ndis_work);
  588     }
  589     EXIT4(return);
  590 }
  591 
  592 /* MiniportSend and MiniportSendPackets */
  593 /* this function is called holding tx_ring_mutex. start and n are such
  594  * that start + n < TX_RING_SIZE; i.e., packets don't wrap around
  595  * ring */
  596 static u8 mp_tx_packets(struct ndis_device *wnd, u8 start, u8 n)
  597 {
  598     NDIS_STATUS res;
  599     struct miniport *mp;
  600     struct ndis_packet *packet;
  601     u8 sent;
  602     KIRQL irql;
  603 
  604     ENTER3("%d, %d", start, n);
  605     mp = &wnd->wd->driver->ndis_driver->mp;
  606     if (mp->send_packets) {
  607         if (deserialized_driver(wnd)) {
  608             LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx,
  609                  &wnd->tx_ring[start], n);
  610             sent = n;
  611         } else {
  612             irql = serialize_lock_irql(wnd);
  613             LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx,
  614                  &wnd->tx_ring[start], n);
  615             serialize_unlock_irql(wnd, irql);
  616             for (sent = 0; sent < n && wnd->tx_ok; sent++) {
  617                 struct ndis_packet_oob_data *oob_data;
  618                 packet = wnd->tx_ring[start + sent];
  619                 oob_data = NDIS_PACKET_OOB_DATA(packet);
  620                 switch ((res =
  621                      xchg(&oob_data->status,
  622                           NDIS_STATUS_NOT_RECOGNIZED))) {
  623                 case NDIS_STATUS_SUCCESS:
  624                     free_tx_packet(wnd, packet,
  625                                NDIS_STATUS_SUCCESS);
  626                     break;
  627                 case NDIS_STATUS_PENDING:
  628                     break;
  629                 case NDIS_STATUS_RESOURCES:
  630                     wnd->tx_ok = 0;
  631                     /* resubmit this packet and
  632                      * the rest when resources
  633                      * become available */
  634                     sent--;
  635                     break;
  636                 case NDIS_STATUS_FAILURE:
  637                     free_tx_packet(wnd, packet,
  638                                NDIS_STATUS_FAILURE);
  639                     break;
  640                 default:
  641                     ERROR("%p: invalid status: %08X",
  642                           packet, res);
  643                     free_tx_packet(wnd, packet,
  644                                oob_data->status);
  645                     break;
  646                 }
  647                 TRACE3("%p, %d", packet, res);
  648             }
  649         }
  650         TRACE3("sent: %d(%d)", sent, n);
  651     } else {
  652         for (sent = 0; sent < n && wnd->tx_ok; sent++) {
  653             struct ndis_packet_oob_data *oob_data;
  654             packet = wnd->tx_ring[start + sent];
  655             oob_data = NDIS_PACKET_OOB_DATA(packet);
  656             oob_data->status = NDIS_STATUS_NOT_RECOGNIZED;
  657             irql = serialize_lock_irql(wnd);
  658             res = LIN2WIN3(mp->send, wnd->nmb->mp_ctx,
  659                        packet, packet->private.flags);
  660             serialize_unlock_irql(wnd, irql);
  661             switch (res) {
  662             case NDIS_STATUS_SUCCESS:
  663                 free_tx_packet(wnd, packet, res);
  664                 break;
  665             case NDIS_STATUS_PENDING:
  666                 break;
  667             case NDIS_STATUS_RESOURCES:
  668                 wnd->tx_ok = 0;
  669                 /* resend this packet when resources
  670                  * become available */
  671                 sent--;
  672                 break;
  673             case NDIS_STATUS_FAILURE:
  674                 free_tx_packet(wnd, packet, res);
  675                 break;
  676             default:
  677                 ERROR("packet %p: invalid status: %08X",
  678                       packet, res);
  679                 break;
  680             }
  681         }
  682     }
  683     EXIT3(return sent);
  684 }
  685 
  686 static void tx_worker(struct work_struct *work)
  687 {
  688     struct ndis_device *wnd;
  689     s8 n;
  690 
  691     wnd = container_of(work, struct ndis_device, tx_work);
  692     ENTER3("tx_ok %d", wnd->tx_ok);
  693     while (wnd->tx_ok) {
  694         mutex_lock(&wnd->tx_ring_mutex);
  695         spin_lock_bh(&wnd->tx_ring_lock);
  696         n = wnd->tx_ring_end - wnd->tx_ring_start;
  697         TRACE3("%d, %d, %d", wnd->tx_ring_start, wnd->tx_ring_end, n);
  698         /* end == start if either ring is empty or full; in
  699          * the latter case is_tx_ring_full is set */
  700         if (n == 0) {
  701             if (wnd->is_tx_ring_full)
  702                 n = TX_RING_SIZE - wnd->tx_ring_start;
  703             else {
  704                 spin_unlock_bh(&wnd->tx_ring_lock);
  705                 mutex_unlock(&wnd->tx_ring_mutex);
  706                 break;
  707             }
  708         } else if (n < 0)
  709             n = TX_RING_SIZE - wnd->tx_ring_start;
  710         spin_unlock_bh(&wnd->tx_ring_lock);
  711         if (unlikely(n > wnd->max_tx_packets))
  712             n = wnd->max_tx_packets;
  713         n = mp_tx_packets(wnd, wnd->tx_ring_start, n);
  714         if (n) {
  715             netif_trans_update(wnd->net_dev);
  716             wnd->tx_ring_start =
  717                 (wnd->tx_ring_start + n) % TX_RING_SIZE;
  718             wnd->is_tx_ring_full = 0;
  719         }
  720         mutex_unlock(&wnd->tx_ring_mutex);
  721         TRACE3("%d, %d, %d", wnd->tx_ring_start, wnd->tx_ring_end, n);
  722     }
  723     EXIT3(return);
  724 }
  725 
  726 static int tx_skbuff(struct sk_buff *skb, struct net_device *dev)
  727 {
  728     struct ndis_device *wnd = netdev_priv(dev);
  729     struct ndis_packet *packet;
  730 
  731     packet = alloc_tx_packet(wnd, skb);
  732     if (!packet) {
  733         TRACE2("couldn't allocate packet");
  734         netif_tx_lock(dev);
  735         netif_stop_queue(dev);
  736         netif_tx_unlock(dev);
  737         return NETDEV_TX_BUSY;
  738     }
  739     spin_lock(&wnd->tx_ring_lock);
  740     wnd->tx_ring[wnd->tx_ring_end++] = packet;
  741     if (wnd->tx_ring_end == TX_RING_SIZE)
  742         wnd->tx_ring_end = 0;
  743     if (wnd->tx_ring_end == wnd->tx_ring_start) {
  744         netif_tx_lock(dev);
  745         wnd->is_tx_ring_full = 1;
  746         netif_stop_queue(dev);
  747         netif_tx_unlock(dev);
  748     }
  749     spin_unlock(&wnd->tx_ring_lock);
  750     TRACE4("ring: %d, %d", wnd->tx_ring_start, wnd->tx_ring_end);
  751     queue_work(wrapndis_wq, &wnd->tx_work);
  752     return NETDEV_TX_OK;
  753 }
  754 
  755 static int set_packet_filter(struct ndis_device *wnd, ULONG packet_filter)
  756 {
  757     NDIS_STATUS res;
  758 
  759     while (1) {
  760         res = mp_set_int(wnd, OID_GEN_CURRENT_PACKET_FILTER,
  761                  packet_filter);
  762         if (res == NDIS_STATUS_SUCCESS)
  763             break;
  764         TRACE2("couldn't set filter 0x%08x", packet_filter);
  765         /* NDIS_PACKET_TYPE_PROMISCUOUS may not work with 802.11 */
  766         if (packet_filter & NDIS_PACKET_TYPE_PROMISCUOUS) {
  767             packet_filter &= ~NDIS_PACKET_TYPE_PROMISCUOUS;
  768             continue;
  769         }
  770         if (packet_filter & NDIS_PACKET_TYPE_ALL_LOCAL) {
  771             packet_filter &= ~NDIS_PACKET_TYPE_ALL_LOCAL;
  772             continue;
  773         }
  774         if (packet_filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) {
  775             packet_filter &= ~NDIS_PACKET_TYPE_ALL_FUNCTIONAL;
  776             continue;
  777         }
  778         if (packet_filter & NDIS_PACKET_TYPE_MULTICAST) {
  779             packet_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
  780             packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
  781             continue;
  782         }
  783         if (packet_filter & NDIS_PACKET_TYPE_ALL_MULTICAST) {
  784             packet_filter &= ~NDIS_PACKET_TYPE_ALL_MULTICAST;
  785             continue;
  786         }
  787         break;
  788     }
  789 
  790     wnd->packet_filter = packet_filter;
  791     res = mp_query_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, &packet_filter);
  792     if (packet_filter != wnd->packet_filter) {
  793         WARNING("filter not set: 0x%08x, 0x%08x",
  794             packet_filter, wnd->packet_filter);
  795         wnd->packet_filter = packet_filter;
  796     }
  797     if (wnd->packet_filter)
  798         EXIT3(return 0);
  799     else
  800         EXIT3(return -1);
  801 }
  802 
  803 void set_media_state(struct ndis_device *wnd, enum ndis_media_state state)
  804 {
  805     struct net_device *net_dev = wnd->net_dev;
  806 
  807     ENTER2("state: 0x%x, carrier %d", state, netif_carrier_ok(net_dev));
  808     switch (state) {
  809     case NdisMediaStateConnected:
  810         if (netif_carrier_ok(net_dev))
  811             return;
  812         netif_carrier_on(net_dev);
  813         wnd->tx_ok = 1;
  814         if (netif_queue_stopped(net_dev))
  815             netif_wake_queue(net_dev);
  816         if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) {
  817             set_bit(LINK_STATUS_ON, &wnd->ndis_pending_work);
  818             queue_work(wrapndis_wq, &wnd->ndis_work);
  819         }
  820         break;
  821     case NdisMediaStateDisconnected:
  822         if (!netif_carrier_ok(net_dev))
  823             return;
  824         netif_carrier_off(net_dev);
  825         netif_stop_queue(net_dev);
  826         wnd->tx_ok = 0;
  827         if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) {
  828             memset(&wnd->essid, 0, sizeof(wnd->essid));
  829             set_bit(LINK_STATUS_OFF, &wnd->ndis_pending_work);
  830             queue_work(wrapndis_wq, &wnd->ndis_work);
  831         }
  832         break;
  833     default:
  834         WARNING("invalid media state: 0x%x", state);
  835         break;
  836     }
  837 }
  838 
  839 static int ndis_net_dev_init(struct net_device *net_dev)
  840 {
  841     struct ndis_device *wnd = netdev_priv(net_dev);
  842 
  843     ENTER1("%p", wnd);
  844     wrap_procfs_add_ndis_device(wnd);
  845     EXIT1(return 0);
  846 }
  847 
  848 static void ndis_net_dev_uninit(struct net_device *net_dev)
  849 {
  850     struct ndis_device *wnd = netdev_priv(net_dev);
  851 
  852     ENTER1("%p", wnd);
  853     wrap_procfs_remove_ndis_device(wnd);
  854     EXIT1(return);
  855 }
  856 
  857 static int ndis_net_dev_open(struct net_device *net_dev)
  858 {
  859     int status, res;
  860     struct ndis_device *wnd = netdev_priv(net_dev);
  861 
  862     ENTER1("%p", wnd);
  863     res = mp_query_int(wnd, OID_GEN_MEDIA_CONNECT_STATUS, &status);
  864     if (res == NDIS_STATUS_SUCCESS && status >= NdisMediaStateConnected &&
  865         status <= NdisMediaStateDisconnected)
  866         set_media_state(wnd, status);
  867     netif_start_queue(net_dev);
  868     netif_poll_enable(net_dev);
  869     EXIT1(return 0);
  870 }
  871 
  872 static int ndis_net_dev_close(struct net_device *net_dev)
  873 {
  874     ENTER1("%p", netdev_priv(net_dev));
  875     netif_poll_disable(net_dev);
  876     netif_tx_disable(net_dev);
  877     EXIT1(return 0);
  878 }
  879 
  880 static int ndis_change_mtu(struct net_device *net_dev, int mtu)
  881 {
  882     struct ndis_device *wnd = netdev_priv(net_dev);
  883     int max;
  884 
  885     if (mtu < ETH_ZLEN)
  886         return -EINVAL;
  887     if (mp_query_int(wnd, OID_GEN_MAXIMUM_TOTAL_SIZE, &max) !=
  888         NDIS_STATUS_SUCCESS)
  889         return -EOPNOTSUPP;
  890     TRACE1("%d", max);
  891     max -= ETH_HLEN;
  892     if (max <= ETH_ZLEN)
  893         return -EINVAL;
  894     if (mtu + ETH_HLEN > max)
  895         return -EINVAL;
  896     net_dev->mtu = mtu;
  897     return 0;
  898 }
  899 
  900 #ifdef CONFIG_NET_POLL_CONTROLLER
  901 static void ndis_poll_controller(struct net_device *dev)
  902 {
  903     struct ndis_device *wnd = netdev_priv(dev);
  904 
  905     disable_irq(dev->irq);
  906     ndis_isr(wnd->mp_interrupt->kinterrupt, wnd->mp_interrupt);
  907     enable_irq(dev->irq);
  908 }
  909 #endif
  910 
  911 /* called from BH context */
  912 static struct net_device_stats *ndis_get_stats(struct net_device *dev)
  913 {
  914     struct ndis_device *wnd = netdev_priv(dev);
  915     return &wnd->net_stats;
  916 }
  917 
  918 /* called from BH context */
  919 static void ndis_set_multicast_list(struct net_device *dev)
  920 {
  921     struct ndis_device *wnd = netdev_priv(dev);
  922     set_bit(SET_MULTICAST_LIST, &wnd->ndis_pending_work);
  923     queue_work(wrapndis_wq, &wnd->ndis_work);
  924 }
  925 
  926 /* called from BH context */
  927 struct iw_statistics *get_iw_stats(struct net_device *dev)
  928 {
  929     struct ndis_device *wnd = netdev_priv(dev);
  930     return &wnd->iw_stats;
  931 }
  932 
  933 static void update_iw_stats(struct ndis_device *wnd)
  934 {
  935     struct iw_statistics *iw_stats = &wnd->iw_stats;
  936     struct ndis_wireless_stats ndis_stats;
  937     NDIS_STATUS res;
  938     ndis_rssi rssi;
  939     int qual;
  940 
  941     ENTER2("%p", wnd);
  942     if (wnd->iw_stats_enabled == FALSE || !netif_carrier_ok(wnd->net_dev)) {
  943         memset(iw_stats, 0, sizeof(*iw_stats));
  944         EXIT2(return);
  945     }
  946     res = mp_query(wnd, OID_802_11_RSSI, &rssi, sizeof(rssi));
  947     if (res == NDIS_STATUS_SUCCESS)
  948         iw_stats->qual.level = rssi;
  949 
  950     qual = 100 * (rssi - WL_NOISE) / (WL_SIGMAX - WL_NOISE);
  951     if (qual < 0)
  952         qual = 0;
  953     else if (qual > 100)
  954         qual = 100;
  955 
  956     iw_stats->qual.noise = WL_NOISE;
  957     iw_stats->qual.qual = qual;
  958 
  959     res = mp_query(wnd, OID_802_11_STATISTICS,
  960                &ndis_stats, sizeof(ndis_stats));
  961     if (res != NDIS_STATUS_SUCCESS)
  962         EXIT2(return);
  963     iw_stats->discard.retries = (unsigned long)ndis_stats.retry +
  964         (unsigned long)ndis_stats.multi_retry;
  965     iw_stats->discard.misc = (unsigned long)ndis_stats.fcs_err +
  966         (unsigned long)ndis_stats.rtss_fail +
  967         (unsigned long)ndis_stats.ack_fail +
  968         (unsigned long)ndis_stats.frame_dup;
  969 
  970     EXIT2(return);
  971 }
  972 
  973 static void set_multicast_list(struct ndis_device *wnd)
  974 {
  975     struct net_device *net_dev;
  976     ULONG packet_filter;
  977     NDIS_STATUS res;
  978 
  979     net_dev = wnd->net_dev;
  980     packet_filter = wnd->packet_filter;
  981 
  982     TRACE2("0x%08x", packet_filter);
  983     if (net_dev->flags & IFF_PROMISC) {
  984         packet_filter |= NDIS_PACKET_TYPE_PROMISCUOUS |
  985             NDIS_PACKET_TYPE_ALL_LOCAL;
  986     } else if (net_dev->flags & IFF_ALLMULTI ||
  987            netdev_mc_count(net_dev) > wnd->multicast_size) {
  988         packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
  989         TRACE2("0x%08x", packet_filter);
  990     } else if (netdev_mc_count(net_dev) > 0) {
  991         int i, size;
  992         char *buf;
  993 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
  994         struct netdev_hw_addr *ha;
  995 #else
  996         struct dev_mc_list *mclist;
  997 #endif
  998         size = min(wnd->multicast_size, netdev_mc_count(net_dev));
  999         TRACE2("%d, %d", wnd->multicast_size, netdev_mc_count(net_dev));
 1000         buf = kmalloc(size * ETH_ALEN, GFP_KERNEL);
 1001         if (!buf) {
 1002             WARNING("couldn't allocate memory");
 1003             EXIT2(return);
 1004         }
 1005 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
 1006         i = 0;
 1007         netdev_for_each_mc_addr(ha, net_dev) {
 1008             if (i >= size)
 1009                 break;
 1010             memcpy(buf + i * ETH_ALEN, ha->addr, ETH_ALEN);
 1011             TRACE2(MACSTRSEP, MAC2STR(ha->addr));
 1012             i++;
 1013         }
 1014 #else
 1015         mclist = net_dev->mc_list;
 1016         for (i = 0; i < size && mclist; mclist = mclist->next) {
 1017             if (mclist->dmi_addrlen != ETH_ALEN)
 1018                 continue;
 1019             memcpy(buf + i * ETH_ALEN, mclist->dmi_addr, ETH_ALEN);
 1020             TRACE2(MACSTRSEP, MAC2STR(mclist->dmi_addr));
 1021             i++;
 1022         }
 1023 #endif
 1024         res = mp_set(wnd, OID_802_3_MULTICAST_LIST, buf, i * ETH_ALEN);
 1025         if (res == NDIS_STATUS_SUCCESS && i > 0)
 1026             packet_filter |= NDIS_PACKET_TYPE_MULTICAST;
 1027         else
 1028             packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
 1029         kfree(buf);
 1030     }
 1031     TRACE2("0x%08x", packet_filter);
 1032     res = set_packet_filter(wnd, packet_filter);
 1033     if (res)
 1034         TRACE1("couldn't set packet filter (%08X)", res);
 1035     EXIT2(return);
 1036 }
 1037 
 1038 static void link_status_off(struct ndis_device *wnd)
 1039 {
 1040 #ifdef CONFIG_WIRELESS_EXT
 1041     union iwreq_data wrqu;
 1042 
 1043     memset(&wrqu, 0, sizeof(wrqu));
 1044     wrqu.ap_addr.sa_family = ARPHRD_ETHER;
 1045     wireless_send_event(wnd->net_dev, SIOCGIWAP, &wrqu, NULL);
 1046 #endif
 1047     EXIT2(return);
 1048 }
 1049 
 1050 static void link_status_on(struct ndis_device *wnd)
 1051 {
 1052 #ifdef CONFIG_WIRELESS_EXT
 1053     struct ndis_assoc_info *ndis_assoc_info;
 1054     union iwreq_data wrqu;
 1055     NDIS_STATUS res;
 1056     const int assoc_size = sizeof(*ndis_assoc_info) + IW_CUSTOM_MAX + 32;
 1057 #endif
 1058 
 1059     ENTER2("");
 1060 #ifdef CONFIG_WIRELESS_EXT
 1061     memset(&wrqu, 0, sizeof(wrqu));
 1062     ndis_assoc_info = kzalloc(assoc_size, GFP_KERNEL);
 1063     if (!ndis_assoc_info) {
 1064         ERROR("couldn't allocate memory");
 1065         goto send_assoc_event;
 1066     }
 1067     res = mp_query(wnd, OID_802_11_ASSOCIATION_INFORMATION,
 1068                ndis_assoc_info, assoc_size);
 1069     if (res) {
 1070         TRACE2("query assoc_info failed (%08X)", res);
 1071         kfree(ndis_assoc_info);
 1072         goto send_assoc_event;
 1073     }
 1074     TRACE2("%u, 0x%x, %u, 0x%x, %u", ndis_assoc_info->length,
 1075            ndis_assoc_info->req_ies, ndis_assoc_info->req_ie_length,
 1076            ndis_assoc_info->resp_ies, ndis_assoc_info->resp_ie_length);
 1077     if (ndis_assoc_info->req_ie_length > 0) {
 1078         wrqu.data.length = ndis_assoc_info->req_ie_length;
 1079         wireless_send_event(wnd->net_dev, IWEVASSOCREQIE, &wrqu,
 1080                     ((char *)ndis_assoc_info) +
 1081                     ndis_assoc_info->offset_req_ies);
 1082     }
 1083     if (ndis_assoc_info->resp_ie_length > 0) {
 1084         wrqu.data.length = ndis_assoc_info->resp_ie_length;
 1085         wireless_send_event(wnd->net_dev, IWEVASSOCRESPIE, &wrqu,
 1086                     ((char *)ndis_assoc_info) +
 1087                     ndis_assoc_info->offset_resp_ies);
 1088     }
 1089     kfree(ndis_assoc_info);
 1090 
 1091 send_assoc_event:
 1092     get_ap_address(wnd, wrqu.ap_addr.sa_data);
 1093     wrqu.ap_addr.sa_family = ARPHRD_ETHER;
 1094     TRACE2(MACSTRSEP, MAC2STR(wrqu.ap_addr.sa_data));
 1095     wireless_send_event(wnd->net_dev, SIOCGIWAP, &wrqu, NULL);
 1096 #endif
 1097     EXIT2(return);
 1098 }
 1099 
 1100 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
 1101 static void iw_stats_timer_proc(struct timer_list *tl)
 1102 #else
 1103 static void iw_stats_timer_proc(unsigned long data)
 1104 #endif
 1105 {
 1106 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
 1107     struct ndis_device *wnd = from_timer(wnd, tl, iw_stats_timer);
 1108 #else
 1109     struct ndis_device *wnd = (struct ndis_device *)data;
 1110 #endif
 1111 
 1112     ENTER2("%d", wnd->iw_stats_interval);
 1113     if (wnd->iw_stats_interval > 0) {
 1114         set_bit(COLLECT_IW_STATS, &wnd->ndis_pending_work);
 1115         queue_work(wrapndis_wq, &wnd->ndis_work);
 1116     }
 1117     mod_timer(&wnd->iw_stats_timer, jiffies + wnd->iw_stats_interval);
 1118 }
 1119 
 1120 static void add_iw_stats_timer(struct ndis_device *wnd)
 1121 {
 1122     if (wnd->physical_medium != NdisPhysicalMediumWirelessLan)
 1123         return;
 1124     if (wnd->iw_stats_interval < 0)
 1125         wnd->iw_stats_interval *= -1;
 1126 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
 1127     timer_setup(&wnd->iw_stats_timer, iw_stats_timer_proc, 0);
 1128 #else
 1129     wnd->iw_stats_timer.data = (unsigned long)wnd;
 1130     wnd->iw_stats_timer.function = iw_stats_timer_proc;
 1131 #endif
 1132     mod_timer(&wnd->iw_stats_timer, jiffies + wnd->iw_stats_interval);
 1133 }
 1134 
 1135 static void del_iw_stats_timer(struct ndis_device *wnd)
 1136 {
 1137     ENTER2("%d", wnd->iw_stats_interval);
 1138     wnd->iw_stats_interval *= -1;
 1139     del_timer_sync(&wnd->iw_stats_timer);
 1140     EXIT2(return);
 1141 }
 1142 
 1143 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
 1144 static void hangcheck_proc(struct timer_list *tl)
 1145 #else
 1146 static void hangcheck_proc(unsigned long data)
 1147 #endif
 1148 {
 1149 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
 1150     struct ndis_device *wnd = from_timer(wnd, tl, hangcheck_timer);
 1151 #else
 1152     struct ndis_device *wnd = (struct ndis_device *)data;
 1153 #endif
 1154 
 1155     ENTER3("%d", wnd->hangcheck_interval);
 1156     if (wnd->hangcheck_interval > 0) {
 1157         set_bit(HANGCHECK, &wnd->ndis_pending_work);
 1158         queue_work(wrapndis_wq, &wnd->ndis_work);
 1159     }
 1160     mod_timer(&wnd->hangcheck_timer, jiffies + wnd->hangcheck_interval);
 1161     EXIT3(return);
 1162 }
 1163 
 1164 void hangcheck_add(struct ndis_device *wnd)
 1165 {
 1166     if (!wnd->wd->driver->ndis_driver->mp.hangcheck ||
 1167         hangcheck_interval < 0)
 1168         EXIT2(return);
 1169 
 1170     if (hangcheck_interval > 0)
 1171         wnd->hangcheck_interval = hangcheck_interval * HZ;
 1172     if (wnd->hangcheck_interval < 0)
 1173         wnd->hangcheck_interval *= -1;
 1174 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
 1175     timer_setup(&wnd->hangcheck_timer, hangcheck_proc, 0);
 1176 #else
 1177     wnd->hangcheck_timer.data = (unsigned long)wnd;
 1178     wnd->hangcheck_timer.function = hangcheck_proc;
 1179 #endif
 1180     mod_timer(&wnd->hangcheck_timer, jiffies + wnd->hangcheck_interval);
 1181     EXIT2(return);
 1182 }
 1183 
 1184 void hangcheck_del(struct ndis_device *wnd)
 1185 {
 1186     ENTER2("%d", wnd->hangcheck_interval);
 1187     if (wnd->hangcheck_interval > 0)
 1188         wnd->hangcheck_interval *= -1;
 1189     del_timer_sync(&wnd->hangcheck_timer);
 1190     EXIT2(return);
 1191 }
 1192 
 1193 /* worker procedure to take care of setting/checking various states */
 1194 static void wrapndis_worker(struct work_struct *work)
 1195 {
 1196     struct ndis_device *wnd;
 1197 
 1198     wnd = container_of(work, struct ndis_device, ndis_work);
 1199     WORKTRACE("0x%lx", wnd->ndis_pending_work);
 1200 
 1201     if (test_and_clear_bit(NETIF_WAKEQ, &wnd->ndis_pending_work)) {
 1202         netif_tx_lock_bh(wnd->net_dev);
 1203         netif_wake_queue(wnd->net_dev);
 1204         netif_tx_unlock_bh(wnd->net_dev);
 1205     }
 1206 
 1207     if (test_and_clear_bit(LINK_STATUS_OFF, &wnd->ndis_pending_work))
 1208         link_status_off(wnd);
 1209 
 1210     if (test_and_clear_bit(LINK_STATUS_ON, &wnd->ndis_pending_work))
 1211         link_status_on(wnd);
 1212 
 1213     if (test_and_clear_bit(COLLECT_IW_STATS, &wnd->ndis_pending_work))
 1214         update_iw_stats(wnd);
 1215 
 1216     if (test_and_clear_bit(SET_MULTICAST_LIST,
 1217                    &wnd->ndis_pending_work))
 1218         set_multicast_list(wnd);
 1219 
 1220     if (test_and_clear_bit(HANGCHECK, &wnd->ndis_pending_work)) {
 1221         struct miniport *mp;
 1222         BOOLEAN reset;
 1223         KIRQL irql;
 1224 
 1225         mp = &wnd->wd->driver->ndis_driver->mp;
 1226         irql = serialize_lock_irql(wnd);
 1227         reset = LIN2WIN1(mp->hangcheck, wnd->nmb->mp_ctx);
 1228         serialize_unlock_irql(wnd, irql);
 1229         if (reset) {
 1230             TRACE2("%s needs reset", wnd->net_dev->name);
 1231             mp_reset(wnd);
 1232         }
 1233     }
 1234     WORKEXIT(return);
 1235 }
 1236 
 1237 NDIS_STATUS ndis_reinit(struct ndis_device *wnd)
 1238 {
 1239     NDIS_STATUS status;
 1240 
 1241     wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;
 1242     status = mp_set_power_state(wnd, NdisDeviceStateD3);
 1243     if (status != NDIS_STATUS_SUCCESS) {
 1244         ERROR("halting device %s failed: %08X", wnd->net_dev->name,
 1245               status);
 1246         return status;
 1247     }
 1248     status = mp_set_power_state(wnd, NdisDeviceStateD0);
 1249     if (status != NDIS_STATUS_SUCCESS)
 1250         ERROR("starting device %s failed: %08X", wnd->net_dev->name,
 1251               status);
 1252     return status;
 1253 }
 1254 
 1255 #ifdef CONFIG_WIRELESS_EXT
 1256 static void get_encryption_capa(struct ndis_device *wnd, char *buf,
 1257                 const int buf_len)
 1258 {
 1259     int i, mode;
 1260     NDIS_STATUS res;
 1261     struct ndis_assoc_info ndis_assoc_info;
 1262     struct ndis_add_key ndis_key;
 1263     struct ndis_capability *c;
 1264 
 1265     ENTER1("%p", wnd);
 1266     /* set network type to g, b, or a, in that order */
 1267     res = mp_query(wnd, OID_802_11_NETWORK_TYPES_SUPPORTED, buf, buf_len);
 1268     if (res == NDIS_STATUS_SUCCESS) {
 1269         struct network_type_list *net_types;
 1270         unsigned long types = 0;
 1271         net_types = (typeof(net_types))buf;
 1272         for (i = 0; i < net_types->num; i++) {
 1273             TRACE2("%d", net_types->types[i]);
 1274             set_bit(net_types->types[i], &types);
 1275         }
 1276         if (test_bit(Ndis802_11OFDM24, &types))
 1277             mode = Ndis802_11OFDM24;
 1278         else if (test_bit(Ndis802_11DS, &types))
 1279             mode = Ndis802_11DS;
 1280         else if (test_bit(Ndis802_11OFDM5, &types))
 1281             mode = Ndis802_11OFDM5;
 1282         else
 1283             mode = Ndis802_11DS;
 1284         mp_set_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE, mode);
 1285     }
 1286     /* check if WEP is supported */
 1287     if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104,
 1288                  IW_AUTH_CIPHER_NONE) == 0 &&
 1289         get_ndis_encr_mode(wnd) == Ndis802_11Encryption1KeyAbsent)
 1290         set_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr);
 1291 
 1292     /* check if WPA is supported */
 1293     if (set_ndis_auth_mode(wnd, Ndis802_11AuthModeWPA) == 0 &&
 1294         get_ndis_auth_mode(wnd) == Ndis802_11AuthModeWPA)
 1295         set_bit(Ndis802_11AuthModeWPA, &wnd->capa.encr);
 1296     else
 1297         EXIT1(return);
 1298 
 1299     if (set_ndis_auth_mode(wnd, Ndis802_11AuthModeWPAPSK) == 0 &&
 1300         get_ndis_auth_mode(wnd) == Ndis802_11AuthModeWPAPSK)
 1301         set_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.encr);
 1302 
 1303     /* check for highest encryption */
 1304     mode = 0;
 1305     if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_CCMP,
 1306                  IW_AUTH_CIPHER_NONE) == 0 &&
 1307         (i = get_ndis_encr_mode(wnd)) > 0 &&
 1308         (i == Ndis802_11Encryption3KeyAbsent ||
 1309          i == Ndis802_11Encryption3Enabled))
 1310         mode = Ndis802_11Encryption3Enabled;
 1311     else if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_TKIP,
 1312                   IW_AUTH_CIPHER_NONE) == 0 &&
 1313          (i = get_ndis_encr_mode(wnd)) > 0 &&
 1314          (i == Ndis802_11Encryption2KeyAbsent ||
 1315           i == Ndis802_11Encryption2Enabled))
 1316         mode = Ndis802_11Encryption2Enabled;
 1317     else if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104,
 1318                   IW_AUTH_CIPHER_NONE) == 0 &&
 1319          (i = get_ndis_encr_mode(wnd)) > 0 &&
 1320          (i == Ndis802_11Encryption1KeyAbsent ||
 1321           i == Ndis802_11Encryption1Enabled))
 1322         mode = Ndis802_11Encryption1Enabled;
 1323 
 1324     TRACE1("mode: %d", mode);
 1325     if (mode == 0)
 1326         EXIT1(return);
 1327     set_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr);
 1328     if (mode == Ndis802_11Encryption1Enabled)
 1329         EXIT1(return);
 1330 
 1331     ndis_key.length = 32;
 1332     ndis_key.index = 0xC0000001;
 1333     ndis_key.struct_size = sizeof(ndis_key);
 1334     res = mp_set(wnd, OID_802_11_ADD_KEY, &ndis_key, ndis_key.struct_size);
 1335     TRACE2("%08X, %zu", res, sizeof(ndis_key));
 1336     if (res && res != NDIS_STATUS_INVALID_DATA)
 1337         EXIT1(return);
 1338     res = mp_query(wnd, OID_802_11_ASSOCIATION_INFORMATION,
 1339                &ndis_assoc_info, sizeof(ndis_assoc_info));
 1340     TRACE1("%08X", res);
 1341     if (res == NDIS_STATUS_NOT_SUPPORTED)
 1342         EXIT1(return);
 1343 
 1344     set_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr);
 1345     if (mode == Ndis802_11Encryption3Enabled)
 1346         set_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr);
 1347     /* not all drivers support OID_802_11_CAPABILITY, so we don't
 1348      * know for sure if driver support WPA or WPAPSK; assume
 1349      * WPAPSK */
 1350     set_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.auth);
 1351     wnd->max_pmkids = 1;
 1352 
 1353     memset(buf, 0, buf_len);
 1354     c = (struct ndis_capability *)buf;
 1355     res = mp_query(wnd, OID_802_11_CAPABILITY, buf, buf_len);
 1356     if (!(res == NDIS_STATUS_SUCCESS && c->version == 2))
 1357         EXIT1(return);
 1358     wnd->max_pmkids = c->num_PMKIDs;
 1359 
 1360     for (i = 0; i < c->num_auth_encr_pair; i++) {
 1361         struct ndis_auth_encr_pair *ae;
 1362 
 1363         ae = &c->auth_encr_pair[i];
 1364         if ((char *)(ae + 1) > buf + buf_len)
 1365             break;
 1366         switch (ae->auth_mode) {
 1367         case Ndis802_11AuthModeOpen:
 1368         case Ndis802_11AuthModeShared:
 1369         case Ndis802_11AuthModeWPA:
 1370         case Ndis802_11AuthModeWPAPSK:
 1371         case Ndis802_11AuthModeWPANone:
 1372         case Ndis802_11AuthModeWPA2:
 1373         case Ndis802_11AuthModeWPA2PSK:
 1374             set_bit(ae->auth_mode, &wnd->capa.auth);
 1375             break;
 1376         default:
 1377             WARNING("unknown auth_mode: %d", ae->auth_mode);
 1378             break;
 1379         }
 1380         switch (ae->encr_mode) {
 1381         case Ndis802_11EncryptionDisabled:
 1382         case Ndis802_11Encryption1Enabled:
 1383         case Ndis802_11Encryption2Enabled:
 1384         case Ndis802_11Encryption3Enabled:
 1385             set_bit(ae->encr_mode, &wnd->capa.encr);
 1386             break;
 1387         default:
 1388             WARNING("unknown encr_mode: %d", ae->encr_mode);
 1389             break;
 1390         }
 1391     }
 1392     EXIT1(return);
 1393 }
 1394 #endif
 1395 
 1396 wstdcall NTSTATUS NdisDispatchDeviceControl(struct device_object *fdo,
 1397                         struct irp *irp)
 1398 {
 1399     struct ndis_device *wnd;
 1400 
 1401     TRACE3("fdo: %p", fdo);
 1402     /* for now, we don't have anything interesting here, so pass it
 1403      * down to bus driver */
 1404     wnd = fdo->reserved;
 1405     return IoPassIrpDown(wnd->nmb->pdo, irp);
 1406 }
 1407 WIN_FUNC_DECL(NdisDispatchDeviceControl,2)
 1408 
 1409 wstdcall NTSTATUS NdisDispatchPower(struct device_object *fdo, struct irp *irp)
 1410 {
 1411     struct io_stack_location *irp_sl;
 1412     struct ndis_device *wnd;
 1413     enum ndis_power_state state;
 1414     NTSTATUS status;
 1415     NDIS_STATUS ndis_status;
 1416 
 1417     irp_sl = IoGetCurrentIrpStackLocation(irp);
 1418     wnd = fdo->reserved;
 1419     IOTRACE("fdo: %p, fn: %d:%d, wnd: %p", fdo, irp_sl->major_fn,
 1420         irp_sl->minor_fn, wnd);
 1421     if ((irp_sl->params.power.type == SystemPowerState &&
 1422          irp_sl->params.power.state.system_state > PowerSystemWorking) ||
 1423         (irp_sl->params.power.type == DevicePowerState &&
 1424          irp_sl->params.power.state.device_state > PowerDeviceD0))
 1425         state = NdisDeviceStateD3;
 1426     else
 1427         state = NdisDeviceStateD0;
 1428     switch (irp_sl->minor_fn) {
 1429     case IRP_MN_SET_POWER:
 1430         if (state == NdisDeviceStateD0) {
 1431             status = IoSyncForwardIrp(wnd->nmb->pdo, irp);
 1432             if (status != STATUS_SUCCESS)
 1433                 break;
 1434             ndis_status = mp_set_power_state(wnd, state);
 1435             if (ndis_status != NDIS_STATUS_SUCCESS)
 1436                 WARNING("couldn't set power to %d: %08X",
 1437                     state, ndis_status);
 1438             TRACE2("%s: device resumed", wnd->net_dev->name);
 1439             irp->io_status.status = status = STATUS_SUCCESS;
 1440             IoCompleteRequest(irp, IO_NO_INCREMENT);
 1441             break;
 1442         } else {
 1443             ndis_status = mp_set_power_state(wnd, state);
 1444             /* TODO: handle error case */
 1445             if (ndis_status != NDIS_STATUS_SUCCESS)
 1446                 WARNING("setting power to %d failed: %08X",
 1447                     state, ndis_status);
 1448             status = IoAsyncForwardIrp(wnd->nmb->pdo, irp);
 1449         }
 1450         break;
 1451     case IRP_MN_QUERY_POWER:
 1452         if (wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND) {
 1453             ndis_status = mp_query(wnd, OID_PNP_QUERY_POWER,
 1454                            &state, sizeof(state));
 1455             TRACE2("%d, %08X", state, ndis_status);
 1456             /* this OID must always succeed */
 1457             if (ndis_status != NDIS_STATUS_SUCCESS)
 1458                 TRACE1("query power returns %08X", ndis_status);
 1459             irp->io_status.status = STATUS_SUCCESS;
 1460         } else
 1461             irp->io_status.status = STATUS_SUCCESS;
 1462         status = IoPassIrpDown(wnd->nmb->pdo, irp);
 1463         break;
 1464     case IRP_MN_WAIT_WAKE:
 1465     case IRP_MN_POWER_SEQUENCE:
 1466         /* TODO: implement WAIT_WAKE */
 1467         status = IoPassIrpDown(wnd->nmb->pdo, irp);
 1468         break;
 1469     default:
 1470         status = IoPassIrpDown(wnd->nmb->pdo, irp);
 1471         break;
 1472     }
 1473     IOEXIT(return status);
 1474 }
 1475 WIN_FUNC_DECL(NdisDispatchPower,2)
 1476 
 1477 wstdcall NTSTATUS NdisDispatchPnp(struct device_object *fdo, struct irp *irp)
 1478 {
 1479     struct io_stack_location *irp_sl;
 1480     struct ndis_device *wnd;
 1481     struct device_object *pdo;
 1482     NTSTATUS status;
 1483 
 1484     IOTRACE("fdo: %p, irp: %p", fdo, irp);
 1485     irp_sl = IoGetCurrentIrpStackLocation(irp);
 1486     wnd = fdo->reserved;
 1487     pdo = wnd->nmb->pdo;
 1488     switch (irp_sl->minor_fn) {
 1489     case IRP_MN_START_DEVICE:
 1490         status = IoSyncForwardIrp(pdo, irp);
 1491         if (status != STATUS_SUCCESS)
 1492             break;
 1493         if (ndis_start_device(wnd) == NDIS_STATUS_SUCCESS)
 1494             status = STATUS_SUCCESS;
 1495         else
 1496             status = STATUS_FAILURE;
 1497         irp->io_status.status = status;
 1498         IoCompleteRequest(irp, IO_NO_INCREMENT);
 1499         break;
 1500     case IRP_MN_QUERY_STOP_DEVICE:
 1501         /* TODO: implement in NDIS */
 1502         status = IoPassIrpDown(wnd->nmb->pdo, irp);
 1503         break;
 1504     case IRP_MN_STOP_DEVICE:
 1505         mp_halt(wnd);
 1506         irp->io_status.status = STATUS_SUCCESS;
 1507         status = IoAsyncForwardIrp(pdo, irp);
 1508         break;
 1509     case IRP_MN_REMOVE_DEVICE:
 1510         TRACE1("%s", wnd->net_dev->name);
 1511         mp_pnp_event(wnd, NdisDevicePnPEventSurpriseRemoved, 0);
 1512         if (ndis_remove_device(wnd)) {
 1513             status = STATUS_FAILURE;
 1514             break;
 1515         }
 1516         /* wnd is already freed */
 1517         status = IoAsyncForwardIrp(pdo, irp);
 1518         IoDetachDevice(fdo);
 1519         IoDeleteDevice(fdo);
 1520         break;
 1521     default:
 1522         status = IoAsyncForwardIrp(pdo, irp);
 1523         break;
 1524     }
 1525     IOTRACE("status: %08X", status);
 1526     IOEXIT(return status);
 1527 }
 1528 WIN_FUNC_DECL(NdisDispatchPnp,2)
 1529 
 1530 static void set_task_offload(struct ndis_device *wnd, void *buf,
 1531                  const int buf_size)
 1532 {
 1533     struct ndis_task_offload_header *task_offload_header;
 1534     struct ndis_task_offload *task_offload;
 1535     struct ndis_task_tcp_ip_checksum *csum = NULL;
 1536     struct ndis_task_tcp_large_send *tso = NULL;
 1537     NDIS_STATUS status;
 1538 
 1539     memset(buf, 0, buf_size);
 1540     task_offload_header = buf;
 1541     task_offload_header->version = NDIS_TASK_OFFLOAD_VERSION;
 1542     task_offload_header->size = sizeof(*task_offload_header);
 1543     task_offload_header->encap_format.flags.fixed_header_size = 1;
 1544     task_offload_header->encap_format.header_size = sizeof(struct ethhdr);
 1545     task_offload_header->encap_format.encap = IEEE_802_3_Encapsulation;
 1546     status = mp_query(wnd, OID_TCP_TASK_OFFLOAD, buf, buf_size);
 1547     TRACE1("%08X", status);
 1548     if (status != NDIS_STATUS_SUCCESS)
 1549         EXIT1(return);
 1550     if (task_offload_header->offset_first_task == 0)
 1551         EXIT1(return);
 1552     task_offload = ((void *)task_offload_header +
 1553             task_offload_header->offset_first_task);
 1554     while (1) {
 1555         TRACE1("%d, %d", task_offload->version, task_offload->task);
 1556         switch (task_offload->task) {
 1557         case TcpIpChecksumNdisTask:
 1558             csum = (void *)task_offload->task_buf;
 1559             break;
 1560         case TcpLargeSendNdisTask:
 1561             tso = (void *)task_offload->task_buf;
 1562             break;
 1563         default:
 1564             TRACE1("%d", task_offload->task);
 1565             break;
 1566         }
 1567         if (task_offload->offset_next_task == 0)
 1568             break;
 1569         task_offload = (void *)task_offload +
 1570             task_offload->offset_next_task;
 1571     }
 1572     if (tso)
 1573         TRACE1("%u, %u, %d, %d", tso->max_size, tso->min_seg_count,
 1574                tso->tcp_opts, tso->ip_opts);
 1575     if (!csum)
 1576         EXIT1(return);
 1577     TRACE1("%08x, %08x", csum->v4_tx.value, csum->v4_rx.value);
 1578     task_offload_header->encap_format.flags.fixed_header_size = 1;
 1579     task_offload_header->encap_format.header_size = sizeof(struct ethhdr);
 1580     task_offload_header->offset_first_task = sizeof(*task_offload_header);
 1581     task_offload = ((void *)task_offload_header +
 1582             task_offload_header->offset_first_task);
 1583     task_offload->offset_next_task = 0;
 1584     task_offload->size = sizeof(*task_offload);
 1585     task_offload->task = TcpIpChecksumNdisTask;
 1586     memcpy(task_offload->task_buf, csum, sizeof(*csum));
 1587     task_offload->task_buf_length = sizeof(*csum);
 1588     status = mp_set(wnd, OID_TCP_TASK_OFFLOAD, task_offload_header,
 1589             sizeof(*task_offload_header) +
 1590             sizeof(*task_offload) + sizeof(*csum));
 1591     TRACE1("%08X", status);
 1592     if (status != NDIS_STATUS_SUCCESS)
 1593         EXIT2(return);
 1594     wnd->tx_csum = csum->v4_tx;
 1595     if (csum->v4_tx.tcp_csum && csum->v4_tx.udp_csum) {
 1596         if (csum->v4_tx.ip_csum) {
 1597             wnd->net_dev->features |= NETIF_F_HW_CSUM;
 1598             TRACE1("hw checksum enabled");
 1599         } else {
 1600             wnd->net_dev->features |= NETIF_F_IP_CSUM;
 1601             TRACE1("IP checksum enabled");
 1602         }
 1603         if (wnd->sg_dma_size)
 1604             wnd->net_dev->features |= NETIF_F_SG;
 1605     }
 1606     wnd->rx_csum = csum->v4_rx;
 1607     EXIT1(return);
 1608 }
 1609 
 1610 static void get_supported_oids(struct ndis_device *wnd)
 1611 {
 1612     NDIS_STATUS res;
 1613     int i, n, needed;
 1614     ndis_oid *oids;
 1615 
 1616     res = mp_query_info(wnd, OID_GEN_SUPPORTED_LIST, NULL, 0, NULL,
 1617                 &needed);
 1618     if (!(res == NDIS_STATUS_BUFFER_TOO_SHORT ||
 1619           res == NDIS_STATUS_INVALID_LENGTH))
 1620         EXIT1(return);
 1621     oids = kmalloc(needed, GFP_KERNEL);
 1622     if (!oids) {
 1623         TRACE1("couldn't allocate memory");
 1624         EXIT1(return);
 1625     }
 1626     res = mp_query(wnd, OID_GEN_SUPPORTED_LIST, oids, needed);
 1627     if (res) {
 1628         TRACE1("failed: %08X", res);
 1629         kfree(oids);
 1630         EXIT1(return);
 1631     }
 1632     for (i = 0, n = needed / sizeof(*oids); i < n; i++) {
 1633         TRACE1("oid: %08X", oids[i]);
 1634         /* if a wireless device didn't say so for
 1635          * OID_GEN_PHYSICAL_MEDIUM (they should, but in case) */
 1636         if (wnd->physical_medium != NdisPhysicalMediumWirelessLan &&
 1637             oids[i] == OID_802_11_SSID)
 1638             wnd->physical_medium = NdisPhysicalMediumWirelessLan;
 1639     }
 1640     kfree(oids);
 1641     EXIT1(return);
 1642 }
 1643 
 1644 static void ndis_get_drvinfo(struct net_device *dev,
 1645                  struct ethtool_drvinfo *info)
 1646 {
 1647     struct ndis_device *wnd = netdev_priv(dev);
 1648     strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 2);
 1649     strcat(info->driver, "+");
 1650     strncat(info->driver, wnd->wd->driver->name,
 1651         sizeof(info->driver) - strlen(DRIVER_NAME) - 1);
 1652     strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 2);
 1653     strcat(info->version, "+");
 1654     strncat(info->version, wnd->wd->driver->version,
 1655         sizeof(info->version) - strlen(DRIVER_VERSION) - 1);
 1656     if (wrap_is_pci_bus(wnd->wd->dev_bus))
 1657         strncpy(info->bus_info, pci_name(wnd->wd->pci.pdev),
 1658             sizeof(info->bus_info) - 1);
 1659 #ifdef ENABLE_USB
 1660     else
 1661         usb_make_path(wnd->wd->usb.udev, info->bus_info,
 1662                   sizeof(info->bus_info) - 1);
 1663 #endif
 1664     return;
 1665 }
 1666 
 1667 static u32 ndis_get_link(struct net_device *dev)
 1668 {
 1669     struct ndis_device *wnd = netdev_priv(dev);
 1670     return netif_carrier_ok(wnd->net_dev);
 1671 }
 1672 
 1673 static void ndis_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 1674 {
 1675     struct ndis_device *wnd = netdev_priv(dev);
 1676 
 1677     wol->supported = 0;
 1678     wol->wolopts = 0;
 1679     if (!(wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND))
 1680         EXIT2(return);
 1681     if (!wrap_is_pci_bus(wnd->wd->dev_bus))
 1682         EXIT2(return);
 1683     /* we always suspend to D3 */
 1684     if (wnd->pnp_capa.wakeup.min_magic_packet_wakeup < NdisDeviceStateD3)
 1685         return;
 1686     wol->supported |= WAKE_MAGIC;
 1687     if (wnd->ndis_wolopts & NDIS_PNP_WAKE_UP_MAGIC_PACKET)
 1688         wol->wolopts |= WAKE_MAGIC;
 1689     return;
 1690 }
 1691 
 1692 static int ndis_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 1693 {
 1694     struct ndis_device *wnd = netdev_priv(dev);
 1695 
 1696     if (!(wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND))
 1697         return -EOPNOTSUPP;
 1698     if (wnd->pnp_capa.wakeup.min_magic_packet_wakeup < NdisDeviceStateD3)
 1699         EXIT2(return -EOPNOTSUPP);
 1700     TRACE2("0x%x", wol->wolopts);
 1701     if (wol->wolopts & WAKE_MAGIC) {
 1702         wnd->ndis_wolopts |= NDIS_PNP_WAKE_UP_MAGIC_PACKET;
 1703         if (wol->wolopts != WAKE_MAGIC)
 1704             WARNING("ignored wake-on-lan options: 0x%x",
 1705                 wol->wolopts & ~WAKE_MAGIC);
 1706     } else if (!wol->wolopts)
 1707         wnd->ndis_wolopts = 0;
 1708     else
 1709         return -EOPNOTSUPP;
 1710     TRACE2("0x%x", wnd->ndis_wolopts);
 1711     return 0;
 1712 }
 1713 
 1714 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)
 1715 static u32 ndis_get_tx_csum(struct net_device *dev)
 1716 {
 1717     struct ndis_device *wnd = netdev_priv(dev);
 1718     if (wnd->tx_csum.tcp_csum && wnd->tx_csum.udp_csum)
 1719         return 1;
 1720     else
 1721         return 0;
 1722 }
 1723 
 1724 static u32 ndis_get_rx_csum(struct net_device *dev)
 1725 {
 1726     struct ndis_device *wnd = netdev_priv(dev);
 1727     if (wnd->rx_csum.value)
 1728         return 1;
 1729     else
 1730         return 0;
 1731 }
 1732 
 1733 static int ndis_set_tx_csum(struct net_device *dev, u32 data)
 1734 {
 1735     struct ndis_device *wnd = netdev_priv(dev);
 1736 
 1737     if (data && (wnd->tx_csum.value == 0))
 1738         return -EOPNOTSUPP;
 1739 
 1740     if (wnd->tx_csum.ip_csum)
 1741         ethtool_op_set_tx_hw_csum(dev, data);
 1742     else
 1743         ethtool_op_set_tx_csum(dev, data);
 1744     return 0;
 1745 }
 1746 
 1747 static int ndis_set_rx_csum(struct net_device *dev, u32 data)
 1748 {
 1749     struct ndis_device *wnd = netdev_priv(dev);
 1750 
 1751     if (data && (wnd->tx_csum.value == 0))
 1752         return -EOPNOTSUPP;
 1753 
 1754     /* TODO: enable/disable rx csum through NDIS */
 1755     return 0;
 1756 }
 1757 
 1758 static u32 ndis_get_sg(struct net_device *dev)
 1759 {
 1760     struct ndis_device *wnd = netdev_priv(dev);
 1761     if (wnd->sg_dma_size)
 1762         return ethtool_op_get_sg(dev);
 1763     else
 1764         return 0;
 1765 }
 1766 
 1767 static int ndis_set_sg(struct net_device *dev, u32 data)
 1768 {
 1769     struct ndis_device *wnd = netdev_priv(dev);
 1770     if (wnd->sg_dma_size)
 1771         return ethtool_op_set_sg(dev, data);
 1772     else
 1773         return -EOPNOTSUPP;
 1774 }
 1775 #endif
 1776 
 1777 static struct ethtool_ops ndis_ethtool_ops = {
 1778     .get_drvinfo    = ndis_get_drvinfo,
 1779     .get_link   = ndis_get_link,
 1780     .get_wol    = ndis_get_wol,
 1781     .set_wol    = ndis_set_wol,
 1782 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)
 1783     .get_tx_csum    = ndis_get_tx_csum,
 1784     .get_rx_csum    = ndis_get_rx_csum,
 1785     .set_tx_csum    = ndis_set_tx_csum,
 1786     .set_rx_csum    = ndis_set_rx_csum,
 1787     .get_sg     = ndis_get_sg,
 1788     .set_sg     = ndis_set_sg,
 1789 #endif
 1790 };
 1791 
 1792 static int notifier_event(struct notifier_block *notifier, unsigned long event,
 1793               void *ptr)
 1794 {
 1795     struct net_device *net_dev = netdev_notifier_info_to_dev(ptr);
 1796 
 1797     ENTER2("0x%lx", event);
 1798     if (net_dev->ethtool_ops == &ndis_ethtool_ops
 1799         && event == NETDEV_CHANGENAME) {
 1800         struct ndis_device *wnd = netdev_priv(net_dev);
 1801 
 1802         /* called with rtnl lock held, so no need to lock */
 1803         if (likely(wnd->procfs_iface)) {
 1804             printk(KERN_INFO "%s: interface renamed to '%s'\n",
 1805                    DRIVER_NAME, net_dev->name);
 1806             wrap_procfs_remove_ndis_device(wnd);
 1807             wrap_procfs_add_ndis_device(wnd);
 1808         }
 1809     }
 1810     return NOTIFY_DONE;
 1811 }
 1812 
 1813 static struct notifier_block netdev_notifier = {
 1814     .notifier_call = notifier_event,
 1815 };
 1816 
 1817 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
 1818 static const struct net_device_ops ndis_netdev_ops = {
 1819     .ndo_init = ndis_net_dev_init,
 1820     .ndo_uninit = ndis_net_dev_uninit,
 1821     .ndo_open = ndis_net_dev_open,
 1822     .ndo_stop = ndis_net_dev_close,
 1823     .ndo_start_xmit = tx_skbuff,
 1824     .ndo_change_mtu = ndis_change_mtu,
 1825 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
 1826     .ndo_set_rx_mode = ndis_set_multicast_list,
 1827 #else
 1828     .ndo_set_multicast_list = ndis_set_multicast_list,
 1829 #endif
 1830     .ndo_set_mac_address = ndis_set_mac_address,
 1831     .ndo_get_stats = ndis_get_stats,
 1832 #ifdef CONFIG_NET_POLL_CONTROLLER
 1833     .ndo_poll_controller = ndis_poll_controller,
 1834 #endif
 1835 };
 1836 #endif
 1837 
 1838 static NDIS_STATUS ndis_start_device(struct ndis_device *wnd)
 1839 {
 1840     struct wrap_device *wd;
 1841     struct net_device *net_dev;
 1842     NDIS_STATUS status;
 1843     char *buf;
 1844     const int buf_len = 256;
 1845     mac_address mac;
 1846     struct transport_header_offset *tx_header_offset;
 1847     int n;
 1848 
 1849     ENTER2("%d", in_atomic());
 1850     status = mp_init(wnd);
 1851     if (status == NDIS_STATUS_NOT_RECOGNIZED)
 1852         EXIT1(return NDIS_STATUS_SUCCESS);
 1853     if (status != NDIS_STATUS_SUCCESS)
 1854         EXIT1(return status);
 1855     wd = wnd->wd;
 1856     net_dev = wnd->net_dev;
 1857 
 1858     get_supported_oids(wnd);
 1859     memset(mac, 0, sizeof(mac));
 1860     status = mp_query(wnd, OID_802_3_CURRENT_ADDRESS, mac, sizeof(mac));
 1861     if (memcmp(mac, "\x00\x00\x00\x00\x00\x00", sizeof(mac)) == 0) {
 1862         status = mp_query(wnd, OID_802_3_PERMANENT_ADDRESS, mac,
 1863                   sizeof(mac));
 1864         if (status != NDIS_STATUS_SUCCESS) {
 1865             ERROR("couldn't get mac address: %08X", status);
 1866             goto err_start;
 1867         }
 1868     }
 1869     TRACE1("mac:" MACSTRSEP, MAC2STR(mac));
 1870     memcpy(net_dev->dev_addr, mac, ETH_ALEN);
 1871 
 1872     strncpy(net_dev->name, if_name, IFNAMSIZ - 1);
 1873     net_dev->name[IFNAMSIZ - 1] = 0;
 1874 
 1875     wnd->packet_filter = NDIS_PACKET_TYPE_DIRECTED |
 1876         NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_MULTICAST;
 1877 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
 1878     net_dev->netdev_ops = &ndis_netdev_ops;
 1879 #else
 1880     net_dev->init = ndis_net_dev_init;
 1881     net_dev->uninit = ndis_net_dev_uninit;
 1882     net_dev->open = ndis_net_dev_open;
 1883     net_dev->hard_start_xmit = tx_skbuff;
 1884     net_dev->stop = ndis_net_dev_close;
 1885     net_dev->get_stats = ndis_get_stats;
 1886     net_dev->change_mtu = ndis_change_mtu;
 1887     net_dev->set_multicast_list = ndis_set_multicast_list;
 1888     net_dev->set_mac_address = ndis_set_mac_address;
 1889 #ifdef CONFIG_NET_POLL_CONTROLLER
 1890     net_dev->poll_controller = ndis_poll_controller;
 1891 #endif
 1892 #endif
 1893 #ifdef CONFIG_WIRELESS_EXT
 1894     if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) {
 1895         net_dev->wireless_handlers = &ndis_handler_def;
 1896     }
 1897 #endif
 1898     net_dev->ethtool_ops = &ndis_ethtool_ops;
 1899     if (wnd->mp_interrupt)
 1900         net_dev->irq = wnd->mp_interrupt->irq;
 1901     net_dev->mem_start = wnd->mem_start;
 1902     net_dev->mem_end = wnd->mem_end;
 1903     status = mp_query_int(wnd, OID_802_3_MAXIMUM_LIST_SIZE,
 1904                   &wnd->multicast_size);
 1905     if (status != NDIS_STATUS_SUCCESS || wnd->multicast_size < 0)
 1906         wnd->multicast_size = 0;
 1907     if (wnd->multicast_size > 0)
 1908         net_dev->flags |= IFF_MULTICAST;
 1909     else
 1910         net_dev->flags &= ~IFF_MULTICAST;
 1911 
 1912     buf = kmalloc(buf_len, GFP_KERNEL);
 1913     if (!buf) {
 1914         WARNING("couldn't allocate memory");
 1915         goto err_start;
 1916     }
 1917 
 1918     set_task_offload(wnd, buf, buf_len);
 1919 #ifdef NETIF_F_LLTX
 1920     net_dev->features |= NETIF_F_LLTX;
 1921 #endif
 1922 
 1923     if (register_netdev(net_dev)) {
 1924         ERROR("cannot register net device %s", net_dev->name);
 1925         goto err_register;
 1926     }
 1927     memset(buf, 0, buf_len);
 1928     status = mp_query(wnd, OID_GEN_VENDOR_DESCRIPTION, buf, buf_len);
 1929     if (status != NDIS_STATUS_SUCCESS) {
 1930         WARNING("couldn't get vendor information: 0x%x", status);
 1931         buf[0] = 0;
 1932     }
 1933     wnd->drv_ndis_version = n = 0;
 1934     mp_query_int(wnd, OID_GEN_DRIVER_VERSION, &wnd->drv_ndis_version);
 1935     mp_query_int(wnd, OID_GEN_VENDOR_DRIVER_VERSION, &n);
 1936 
 1937     printk(KERN_INFO "%s: ethernet device " MACSTRSEP " using %sNDIS "
 1938            "driver: %s, version: 0x%x, NDIS version: 0x%x, vendor: '%s', "
 1939            "%s\n", net_dev->name, MAC2STR(net_dev->dev_addr),
 1940            deserialized_driver(wnd) ? "" : "serialized ",
 1941            wd->driver->name, n, wnd->drv_ndis_version, buf,
 1942            wd->conf_file_name);
 1943 
 1944     if (deserialized_driver(wnd)) {
 1945         /* deserialized drivers don't have a limit, but we
 1946          * keep max at TX_RING_SIZE */
 1947         wnd->max_tx_packets = TX_RING_SIZE;
 1948     } else {
 1949         status = mp_query_int(wnd, OID_GEN_MAXIMUM_SEND_PACKETS,
 1950                       &wnd->max_tx_packets);
 1951         if (status != NDIS_STATUS_SUCCESS)
 1952             wnd->max_tx_packets = 1;
 1953         if (wnd->max_tx_packets > TX_RING_SIZE)
 1954             wnd->max_tx_packets = TX_RING_SIZE;
 1955     }
 1956     TRACE2("maximum send packets: %d", wnd->max_tx_packets);
 1957     NdisAllocatePacketPoolEx(&status, &wnd->tx_packet_pool,
 1958                  wnd->max_tx_packets, 0,
 1959                  PROTOCOL_RESERVED_SIZE_IN_PACKET);
 1960     if (status != NDIS_STATUS_SUCCESS) {
 1961         ERROR("couldn't allocate packet pool");
 1962         goto packet_pool_err;
 1963     }
 1964     NdisAllocateBufferPool(&status, &wnd->tx_buffer_pool,
 1965                    wnd->max_tx_packets + 4);
 1966     if (status != NDIS_STATUS_SUCCESS) {
 1967         ERROR("couldn't allocate buffer pool");
 1968         goto buffer_pool_err;
 1969     }
 1970     TRACE1("pool: %p", wnd->tx_buffer_pool);
 1971 
 1972     if (mp_query_int(wnd, OID_GEN_MAXIMUM_TOTAL_SIZE, &n) ==
 1973         NDIS_STATUS_SUCCESS && n > ETH_HLEN)
 1974         ndis_change_mtu(wnd->net_dev, n - ETH_HLEN);
 1975 
 1976     if (mp_query_int(wnd, OID_GEN_MAC_OPTIONS, &n) == NDIS_STATUS_SUCCESS)
 1977         TRACE2("mac options supported: 0x%x", n);
 1978 
 1979     tx_header_offset = (typeof(tx_header_offset))buf;
 1980     tx_header_offset->protocol_type = NDIS_PROTOCOL_ID_TCP_IP;
 1981     tx_header_offset->header_offset = sizeof(ETH_HLEN);
 1982     status = mp_set(wnd, OID_GEN_TRANSPORT_HEADER_OFFSET,
 1983             tx_header_offset, sizeof(*tx_header_offset));
 1984     TRACE2("%08X", status);
 1985 
 1986     status = mp_query_int(wnd, OID_GEN_PHYSICAL_MEDIUM,
 1987                   &wnd->physical_medium);
 1988     if (status != NDIS_STATUS_SUCCESS)
 1989         wnd->physical_medium = NdisPhysicalMediumUnspecified;
 1990 
 1991 #ifdef CONFIG_WIRELESS_EXT
 1992     if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) {
 1993         mp_set_int(wnd, OID_802_11_POWER_MODE, NDIS_POWER_OFF);
 1994         get_encryption_capa(wnd, buf, buf_len);
 1995         TRACE1("capabilities = %ld", wnd->capa.encr);
 1996         printk(KERN_INFO "%s: encryption modes supported: "
 1997                "%s%s%s%s%s%s%s\n", net_dev->name,
 1998                test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr) ?
 1999                "WEP" : "none",
 2000 
 2001                test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr) ?
 2002                "; TKIP with WPA" : "",
 2003                test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ?
 2004                ", WPA2" : "",
 2005                test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ?
 2006                ", WPA2-PSK" : "",
 2007 
 2008                test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr) ?
 2009                "; AES/CCMP with WPA" : "",
 2010                test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ?
 2011                ", WPA2" : "",
 2012                test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ?
 2013                ", WPA2-PSK" : "");
 2014 
 2015         set_default_iw_params(wnd);
 2016     }
 2017 #endif
 2018     kfree(buf);
 2019     hangcheck_add(wnd);
 2020     add_iw_stats_timer(wnd);
 2021     EXIT1(return NDIS_STATUS_SUCCESS);
 2022 
 2023 buffer_pool_err:
 2024     wnd->tx_buffer_pool = NULL;
 2025     if (wnd->tx_packet_pool) {
 2026         NdisFreePacketPool(wnd->tx_packet_pool);
 2027         wnd->tx_packet_pool = NULL;
 2028     }
 2029 packet_pool_err:
 2030     unregister_netdev(net_dev);
 2031     wnd->max_tx_packets = 0;
 2032 err_register:
 2033     kfree(buf);
 2034 err_start:
 2035     mp_halt(wnd);
 2036     EXIT1(return NDIS_STATUS_FAILURE);
 2037 }
 2038 
 2039 static int ndis_remove_device(struct ndis_device *wnd)
 2040 {
 2041     s8 tx_pending;
 2042     int our_mutex;
 2043 
 2044     /* prevent setting essid during disassociation */
 2045     memset(&wnd->essid, 0, sizeof(wnd->essid));
 2046     wnd->tx_ok = 0;
 2047     netif_carrier_off(wnd->net_dev);
 2048     if (wnd->max_tx_packets)
 2049         unregister_netdev(wnd->net_dev);
 2050     /* if device is suspended, but resume failed, tx_ring_mutex
 2051      * may already be locked */
 2052     our_mutex = mutex_trylock(&wnd->tx_ring_mutex);
 2053     if (!our_mutex)
 2054         WARNING("couldn't obtain tx_ring_mutex");
 2055     spin_lock_bh(&wnd->tx_ring_lock);
 2056     tx_pending = wnd->tx_ring_end - wnd->tx_ring_start;
 2057     if (tx_pending < 0)
 2058         tx_pending += TX_RING_SIZE;
 2059     else if (tx_pending == 0 && wnd->is_tx_ring_full)
 2060         tx_pending = TX_RING_SIZE - 1;
 2061     wnd->is_tx_ring_full = 0;
 2062     /* throw away pending packets */
 2063     while (tx_pending-- > 0) {
 2064         struct ndis_packet *packet;
 2065 
 2066         packet = wnd->tx_ring[wnd->tx_ring_start];
 2067         free_tx_packet(wnd, packet, NDIS_STATUS_CLOSING);
 2068         wnd->tx_ring_start = (wnd->tx_ring_start + 1) % TX_RING_SIZE;
 2069     }
 2070     spin_unlock_bh(&wnd->tx_ring_lock);
 2071     if (our_mutex)
 2072         mutex_unlock(&wnd->tx_ring_mutex);
 2073     mp_halt(wnd);
 2074     ndis_exit_device(wnd);
 2075 
 2076     if (wnd->tx_packet_pool) {
 2077         NdisFreePacketPool(wnd->tx_packet_pool);
 2078         wnd->tx_packet_pool = NULL;
 2079     }
 2080     if (wnd->tx_buffer_pool) {
 2081         NdisFreeBufferPool(wnd->tx_buffer_pool);
 2082         wnd->tx_buffer_pool = NULL;
 2083     }
 2084     kfree(wnd->pmkids);
 2085     printk(KERN_INFO "%s: device %s removed\n", DRIVER_NAME,
 2086            wnd->net_dev->name);
 2087     kfree(wnd->nmb);
 2088     free_netdev(wnd->net_dev);
 2089     EXIT2(return 0);
 2090 }
 2091 
 2092 static NTSTATUS ndis_add_device(struct driver_object *drv_obj,
 2093                 struct device_object *pdo)
 2094 {
 2095     struct device_object *fdo;
 2096     struct ndis_mp_block *nmb;
 2097     NTSTATUS status;
 2098     struct ndis_device *wnd;
 2099     struct net_device *net_dev;
 2100     struct wrap_device *wd;
 2101     unsigned long i;
 2102 
 2103     ENTER2("%p, %p", drv_obj, pdo);
 2104     if (strlen(if_name) >= IFNAMSIZ) {
 2105         ERROR("interface name '%s' is too long", if_name);
 2106         return STATUS_INVALID_PARAMETER;
 2107     }
 2108     net_dev = alloc_etherdev(sizeof(*wnd));
 2109     if (!net_dev) {
 2110         ERROR("couldn't allocate device");
 2111         return STATUS_RESOURCES;
 2112     }
 2113     wd = pdo->reserved;
 2114     if (wrap_is_pci_bus(wd->dev_bus))
 2115         SET_NETDEV_DEV(net_dev, &wd->pci.pdev->dev);
 2116     if (wrap_is_usb_bus(wd->dev_bus))
 2117         SET_NETDEV_DEV(net_dev, &wd->usb.intf->dev);
 2118     status = IoCreateDevice(drv_obj, 0, NULL, FILE_DEVICE_UNKNOWN, 0,
 2119                 FALSE, &fdo);
 2120     if (status != STATUS_SUCCESS) {
 2121         free_netdev(net_dev);
 2122         EXIT2(return status);
 2123     }
 2124     wnd = netdev_priv(net_dev);
 2125     TRACE1("wnd: %p", wnd);
 2126 
 2127     nmb = kmalloc(sizeof(*nmb), GFP_KERNEL);
 2128     if (!nmb) {
 2129         WARNING("couldn't allocate memory");
 2130         IoDeleteDevice(fdo);
 2131         free_netdev(net_dev);
 2132         return STATUS_RESOURCES;
 2133     }
 2134 #if DEBUG >= 6
 2135     /* poison nmb so if a driver accesses uninitialized pointers, we
 2136      * know what it is */
 2137     for (i = 0; i < sizeof(*nmb) / sizeof(unsigned long); i++)
 2138         ((unsigned long *)nmb)[i] = i + 0x8a3fc1;
 2139 #endif
 2140 
 2141     wnd->nmb = nmb;
 2142     nmb->wnd = wnd;
 2143     nmb->pdo = pdo;
 2144     wnd->wd = wd;
 2145     wnd->net_dev = net_dev;
 2146     fdo->reserved = wnd;
 2147     nmb->fdo = fdo;
 2148     if (ndis_init_device(wnd)) {
 2149         IoDeleteDevice(fdo);
 2150         kfree(nmb);
 2151         free_netdev(net_dev);
 2152         EXIT1(return STATUS_RESOURCES);
 2153     }
 2154     nmb->next_device = IoAttachDeviceToDeviceStack(fdo, pdo);
 2155     spin_lock_init(&wnd->tx_ring_lock);
 2156     mutex_init(&wnd->tx_ring_mutex);
 2157     mutex_init(&wnd->ndis_req_mutex);
 2158     wnd->ndis_req_done = 0;
 2159     INIT_WORK(&wnd->tx_work, tx_worker);
 2160     wnd->tx_ring_start = 0;
 2161     wnd->tx_ring_end = 0;
 2162     wnd->is_tx_ring_full = 0;
 2163     wnd->capa.encr = 0;
 2164     wnd->capa.auth = 0;
 2165     wnd->attributes = 0;
 2166     wnd->dma_map_count = 0;
 2167     wnd->dma_map_addr = NULL;
 2168     wnd->nick[0] = 0;
 2169 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
 2170     timer_setup(&wnd->hangcheck_timer, hangcheck_proc, 0);
 2171     timer_setup(&wnd->iw_stats_timer, hangcheck_proc, 0);
 2172 #else
 2173     init_timer(&wnd->hangcheck_timer);
 2174     init_timer(&wnd->iw_stats_timer);
 2175 #endif
 2176     wnd->scan_timestamp = 0;
 2177     wnd->iw_stats_interval = 10 * HZ;
 2178     wnd->ndis_pending_work = 0;
 2179     memset(&wnd->essid, 0, sizeof(wnd->essid));
 2180     memset(&wnd->encr_info, 0, sizeof(wnd->encr_info));
 2181     wnd->infrastructure_mode = Ndis802_11Infrastructure;
 2182     INIT_WORK(&wnd->ndis_work, wrapndis_worker);
 2183     wnd->iw_stats_enabled = TRUE;
 2184 
 2185     TRACE1("nmb: %p, pdo: %p, fdo: %p, attached: %p, next: %p",
 2186            nmb, pdo, fdo, fdo->attached, nmb->next_device);
 2187 
 2188     /* dispatch routines are called as Windows functions */
 2189     for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
 2190         drv_obj->major_func[i] = WIN_FUNC_PTR(IoPassIrpDown,2);
 2191 
 2192     drv_obj->major_func[IRP_MJ_PNP] = WIN_FUNC_PTR(NdisDispatchPnp,2);
 2193     drv_obj->major_func[IRP_MJ_POWER] = WIN_FUNC_PTR(NdisDispatchPower,2);
 2194     drv_obj->major_func[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
 2195         WIN_FUNC_PTR(NdisDispatchDeviceControl,2);
 2196 //  drv_obj->major_func[IRP_MJ_DEVICE_CONTROL] =
 2197 //      WIN_FUNC_PTR(NdisDispatchDeviceControl,2);
 2198     EXIT2(return STATUS_SUCCESS);
 2199 }
 2200 
 2201 int init_ndis_driver(struct driver_object *drv_obj)
 2202 {
 2203     ENTER1("%p", drv_obj);
 2204     drv_obj->drv_ext->add_device = ndis_add_device;
 2205     return 0;
 2206 }
 2207 
 2208 int wrapndis_init(void)
 2209 {
 2210     wrapndis_wq = create_singlethread_workqueue("wrapndis_wq");
 2211     if (!wrapndis_wq)
 2212         EXIT1(return -ENOMEM);
 2213     TRACE1("wrapndis_wq: %p", wrapndis_wq);
 2214     register_netdevice_notifier(&netdev_notifier);
 2215     return 0;
 2216 }
 2217 
 2218 void wrapndis_exit(void)
 2219 {
 2220     unregister_netdevice_notifier(&netdev_notifier);
 2221     if (wrapndis_wq)
 2222         destroy_workqueue(wrapndis_wq);
 2223 }