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