~ubuntu-branches/ubuntu/jaunty/ndiswrapper/jaunty

« back to all changes in this revision

Viewing changes to driver/wrapndis.c

  • Committer: Bazaar Package Importer
  • Author(s): Tollef Fog Heen
  • Date: 2006-07-10 14:06:05 UTC
  • mfrom: (1.2.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20060710140605-56bdqtz5m7ze7aw3
Tags: 1.18-1ubuntu1
Sync with Debian.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
#include "loader.h"
20
20
#include "wrapndis.h"
21
21
 
22
 
extern KSPIN_LOCK loader_lock;
23
 
extern struct wrap_device *wrap_devices;
24
 
extern struct nt_list wrap_drivers;
25
 
 
26
22
extern char *if_name;
27
23
extern int hangcheck_interval;
28
 
extern const struct iw_handler_def ndis_handler_def;
 
24
extern struct iw_handler_def ndis_handler_def;
29
25
 
30
26
static int set_packet_filter(struct wrap_ndis_device *wnd,
31
27
                             ULONG packet_filter);
32
 
static void stats_timer_add(struct wrap_ndis_device *wnd);
33
 
static void stats_timer_del(struct wrap_ndis_device *wnd);
 
28
static void add_stats_timer(struct wrap_ndis_device *wnd);
 
29
static void del_stats_timer(struct wrap_ndis_device *wnd);
34
30
static NDIS_STATUS ndis_start_device(struct wrap_ndis_device *wnd);
35
 
static NDIS_STATUS ndis_remove_device(struct wrap_ndis_device *wnd);
 
31
static int ndis_remove_device(struct wrap_ndis_device *wnd);
 
32
static void set_multicast_list(struct wrap_ndis_device *wnd);
36
33
 
37
 
static inline int ndis_wait_pending_completion(struct wrap_ndis_device *wnd)
 
34
static inline int ndis_wait_comm_completion(struct wrap_ndis_device *wnd)
38
35
{
39
 
        /* wait for NdisMXXComplete to be called*/
40
 
        /* As per spec, we should wait until miniport calls back
41
 
         * completion routine, but some drivers (e.g., ZyDas) don't
42
 
         * call back, so timeout is used; TODO: find out why drivers
43
 
         * don't call completion function */
44
 
#if 1
45
 
        /* setting PM state takes a long time, upto 2 seconds, for USB
46
 
         * devices */
47
 
        if (wait_event_interruptible_timeout(wnd->ndis_comm_wq,
48
 
                                             (wnd->ndis_comm_done > 0),
49
 
                                             3 * HZ) <= 0)
50
 
#else
51
 
        if (wait_event_interruptible(wnd->ndis_comm_wq,
52
 
                                     (wnd->ndis_comm_done > 0)))
53
 
#endif
 
36
        if ((wait_event_interruptible(wnd->ndis_comm_wq,
 
37
                                      (wnd->ndis_comm_done > 0))))
54
38
                return -1;
55
39
        else
56
40
                return 0;
59
43
/* MiniportReset */
60
44
NDIS_STATUS miniport_reset(struct wrap_ndis_device *wnd)
61
45
{
62
 
        KIRQL irql;
63
 
        NDIS_STATUS res = 0;
 
46
        NDIS_STATUS res;
64
47
        struct miniport_char *miniport;
65
 
        UINT cur_lookahead;
66
 
        UINT max_lookahead;
 
48
        UINT cur_lookahead, max_lookahead;
67
49
        BOOLEAN reset_address;
 
50
        KIRQL irql;
68
51
 
69
52
        TRACEENTER2("wnd: %p", wnd);
70
53
 
71
 
        if (!test_bit(HW_AVAILABLE, &wnd->hw_status))
72
 
                TRACEEXIT1(return NDIS_STATUS_FAILURE);
73
 
 
74
54
        if (down_interruptible(&wnd->ndis_comm_mutex))
75
55
                TRACEEXIT3(return NDIS_STATUS_FAILURE);
 
56
        down_interruptible(&wnd->tx_ring_mutex);
76
57
        miniport = &wnd->wd->driver->ndis_driver->miniport;
77
58
        cur_lookahead = wnd->nmb->cur_lookahead;
78
59
        max_lookahead = wnd->nmb->max_lookahead;
79
60
        irql = raise_irql(DISPATCH_LEVEL);
80
61
        wnd->ndis_comm_done = 0;
81
 
        res = LIN2WIN2(miniport->reset, &reset_address,
82
 
                       wnd->nmb->adapter_ctx);
 
62
        res = LIN2WIN2(miniport->reset, &reset_address, wnd->nmb->adapter_ctx);
83
63
        lower_irql(irql);
84
64
 
85
 
        DBGTRACE2("res = %08X, reset_status = %08X", res, reset_address);
 
65
        DBGTRACE2("%08X, %08X", res, reset_address);
86
66
        if (res == NDIS_STATUS_PENDING) {
87
67
                /* wait for NdisMResetComplete */
88
 
                if (ndis_wait_pending_completion(wnd))
 
68
                if (ndis_wait_comm_completion(wnd))
89
69
                        res = NDIS_STATUS_FAILURE;
90
70
                else {
91
71
                        res = wnd->ndis_comm_status;
92
72
                        reset_address = wnd->ndis_comm_done - 1;
93
73
                }
94
 
                DBGTRACE2("res = %08X, reset_status = %08X",
95
 
                          res, reset_address);
 
74
                DBGTRACE2("%08X, %08X", res, reset_address);
96
75
        }
97
 
        DBGTRACE2("reset: res = %08X, reset status = %08X",
98
 
                  res, reset_address);
99
 
 
 
76
        up(&wnd->ndis_comm_mutex);
100
77
        if (res == NDIS_STATUS_SUCCESS && reset_address) {
101
78
                wnd->nmb->cur_lookahead = cur_lookahead;
102
79
                wnd->nmb->max_lookahead = max_lookahead;
103
80
                set_packet_filter(wnd, wnd->packet_filter);
104
 
//              set_multicast_list(wnd->net_dev);
 
81
                set_multicast_list(wnd);
105
82
        }
106
 
        up(&wnd->ndis_comm_mutex);
107
 
 
 
83
        up(&wnd->tx_ring_mutex);
108
84
        TRACEEXIT3(return res);
109
85
}
110
86
 
113
89
                                       ndis_oid oid, void *buf,
114
90
                                       ULONG bufsize, ULONG *needed)
115
91
{
116
 
        NDIS_STATUS res = 0;
 
92
        NDIS_STATUS res;
117
93
        ULONG written;
118
94
        struct miniport_char *miniport;
119
95
        KIRQL irql;
120
96
 
121
97
        DBGTRACE2("oid: %08X", oid);
122
98
 
123
 
        if (!test_bit(HW_AVAILABLE, &wnd->hw_status))
124
 
                TRACEEXIT1(return NDIS_STATUS_FAILURE);
125
 
 
126
99
        if (down_interruptible(&wnd->ndis_comm_mutex))
127
100
                TRACEEXIT3(return NDIS_STATUS_FAILURE);
128
101
        miniport = &wnd->wd->driver->ndis_driver->miniport;
129
 
        DBGTRACE2("query %p, oid: %08X", miniport->query, oid);
 
102
        DBGTRACE2("%p, %08X", miniport->query, oid);
130
103
        irql = raise_irql(DISPATCH_LEVEL);
131
104
        wnd->ndis_comm_done = 0;
132
105
        res = LIN2WIN6(miniport->query, wnd->nmb->adapter_ctx, oid, buf,
133
106
                       bufsize, &written, needed);
134
107
        lower_irql(irql);
135
108
 
136
 
        DBGTRACE2("res: %08X, oid: %08X", res, oid);
 
109
        DBGTRACE2("%08X, %08X", res, oid);
137
110
        if (res == NDIS_STATUS_PENDING) {
138
111
                /* wait for NdisMQueryInformationComplete */
139
 
                if (ndis_wait_pending_completion(wnd))
 
112
                if (ndis_wait_comm_completion(wnd))
140
113
                        res = NDIS_STATUS_FAILURE;
141
114
                else
142
115
                        res = wnd->ndis_comm_status;
143
 
                DBGTRACE2("res: %08X", res);
 
116
                DBGTRACE2("%08X, %08X", res, oid);
144
117
        }
145
118
        up(&wnd->ndis_comm_mutex);
146
 
        if (res && needed)
147
 
                DBGTRACE2("res: %08X, bufsize: %d, written: %d, needed: %d",
148
 
                          res, bufsize, written, *needed);
 
119
        DBG_BLOCK(2) {
 
120
                if (res || needed)
 
121
                        DBGTRACE2("%08X, %d, %d, %d", res, bufsize, written,
 
122
                                  *needed);
 
123
        }
149
124
        TRACEEXIT3(return res);
150
125
}
151
126
 
163
138
NDIS_STATUS miniport_set_info(struct wrap_ndis_device *wnd, ndis_oid oid,
164
139
                              void *buf, ULONG bufsize)
165
140
{
166
 
        NDIS_STATUS res = 0;
 
141
        NDIS_STATUS res;
167
142
        ULONG written, needed;
168
143
        struct miniport_char *miniport;
169
144
        KIRQL irql;
170
145
 
171
146
        DBGTRACE2("oid: %08X", oid);
172
147
 
173
 
        if (!test_bit(HW_AVAILABLE, &wnd->hw_status))
174
 
                TRACEEXIT1(return NDIS_STATUS_FAILURE);
175
 
 
176
148
        if (down_interruptible(&wnd->ndis_comm_mutex))
177
149
                TRACEEXIT3(return NDIS_STATUS_FAILURE);
178
150
        miniport = &wnd->wd->driver->ndis_driver->miniport;
179
 
        DBGTRACE2("query %p, oid: %08X", miniport->query, oid);
 
151
        DBGTRACE2("%p, %08X", miniport->query, oid);
180
152
        irql = raise_irql(DISPATCH_LEVEL);
181
153
        wnd->ndis_comm_done = 0;
182
154
        res = LIN2WIN6(miniport->setinfo, wnd->nmb->adapter_ctx, oid,
183
155
                       buf, bufsize, &written, &needed);
184
156
        lower_irql(irql);
185
157
 
186
 
        DBGTRACE2("res: %08X, oid: %08X", res, oid);
 
158
        DBGTRACE2("%08X, %08X", res, oid);
187
159
        if (res == NDIS_STATUS_PENDING) {
188
160
                /* wait for NdisMQueryInformationComplete */
189
 
                if (ndis_wait_pending_completion(wnd))
 
161
                if (ndis_wait_comm_completion(wnd))
190
162
                        res = NDIS_STATUS_FAILURE;
191
163
                else
192
164
                        res = wnd->ndis_comm_status;
193
 
                DBGTRACE2("res: %08X", res);
 
165
                DBGTRACE2("%08X, %08X", res, oid);
194
166
        }
195
167
        up(&wnd->ndis_comm_mutex);
196
 
 
197
 
        if (res && needed)
198
 
                DBGTRACE2("res: %08X, bufsize: %d, written: %d, needed: %d",
199
 
                          res, bufsize, written, needed);
 
168
        DBG_BLOCK(2) {
 
169
                if (res && needed)
 
170
                        DBGTRACE2("%08X, %d, %d, %d", res, bufsize, written,
 
171
                                  needed);
 
172
        }
200
173
        TRACEEXIT3(return res);
201
174
}
202
175
 
212
185
        return miniport_set_info(wnd, oid, &data, sizeof(data));
213
186
}
214
187
 
 
188
/* MiniportPnPEventNotify */
 
189
static NDIS_STATUS miniport_pnp_event(struct wrap_ndis_device *wnd,
 
190
                                      enum ndis_device_pnp_event event)
 
191
{
 
192
        struct miniport_char *miniport;
 
193
        enum ndis_power_profile power_profile;
 
194
 
 
195
        TRACEENTER1("%p, %d", wnd, event);
 
196
        /* RNDIS driver doesn't like to be notified if device is
 
197
         * already halted */
 
198
        if (!test_bit(HW_INITIALIZED, &wnd->hw_status))
 
199
                TRACEEXIT1(return NDIS_STATUS_SUCCESS);
 
200
        miniport = &wnd->wd->driver->ndis_driver->miniport;
 
201
        switch (event) {
 
202
        case NdisDevicePnPEventSurpriseRemoved:
 
203
                DBGTRACE1("%u, %p",
 
204
                          (wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK),
 
205
                          miniport->pnp_event_notify);
 
206
                if ((wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK) &&
 
207
                    miniport->pnp_event_notify) {
 
208
                        DBGTRACE1("calling surprise_removed");
 
209
                        LIN2WIN4(miniport->pnp_event_notify,
 
210
                                 wnd->nmb->adapter_ctx,
 
211
                                 NdisDevicePnPEventSurpriseRemoved, NULL, 0);
 
212
                } else
 
213
                        DBGTRACE1("Windows driver %s doesn't support "
 
214
                                  "MiniportPnpEventNotify for safe unplugging",
 
215
                                  wnd->wd->driver->name);
 
216
                return NDIS_STATUS_SUCCESS;
 
217
        case NdisDevicePnPEventPowerProfileChanged:
 
218
                if (!miniport->pnp_event_notify) {
 
219
                        DBGTRACE1("Windows driver %s doesn't support "
 
220
                                  "MiniportPnpEventNotify",
 
221
                                  wnd->wd->driver->name);
 
222
                        return NDIS_STATUS_FAILURE;
 
223
                }
 
224
                power_profile = NdisPowerProfileAcOnLine;
 
225
                LIN2WIN4(miniport->pnp_event_notify, wnd->nmb->adapter_ctx,
 
226
                         NdisDevicePnPEventPowerProfileChanged,
 
227
                         &power_profile, (ULONG)sizeof(power_profile));
 
228
                return NDIS_STATUS_SUCCESS;
 
229
        default:
 
230
                WARNING("event %d not yet implemented", event);
 
231
                return NDIS_STATUS_SUCCESS;
 
232
        }
 
233
}
 
234
 
 
235
/* MiniportInitialize */
215
236
static NDIS_STATUS miniport_init(struct wrap_ndis_device *wnd)
216
237
{
217
238
        NDIS_STATUS error_status, status;
218
239
        UINT medium_index;
219
240
        UINT medium_array[] = {NdisMedium802_3};
220
241
        struct miniport_char *miniport;
 
242
        struct ndis_pnp_capabilities pnp_capa;
221
243
 
222
244
        TRACEENTER1("irql: %d", current_irql());
223
245
        if (test_bit(HW_INITIALIZED, &wnd->hw_status)) {
224
 
                ERROR("device %p already initialized!", wnd);
 
246
                WARNING("device %p already initialized!", wnd);
225
247
                return NDIS_STATUS_FAILURE;
226
248
        }
227
 
        
 
249
 
228
250
        if (!wnd->wd->driver->ndis_driver ||
229
251
            !wnd->wd->driver->ndis_driver->miniport.init) {
230
 
                ERROR("assuming WDM (non-NDIS) driver");
231
 
                TRACEEXIT1(return NDIS_STATUS_SUCCESS);
 
252
                WARNING("assuming WDM (non-NDIS) driver");
 
253
                TRACEEXIT1(return NDIS_STATUS_NOT_RECOGNIZED);
232
254
        }
233
255
        miniport = &wnd->wd->driver->ndis_driver->miniport;
234
256
        status = LIN2WIN6(miniport->init, &error_status,
242
264
        }
243
265
 
244
266
        /* Wait a little to let card power up otherwise ifup might
245
 
         * fail after boot; USB devices seem to need long delays */
246
 
        set_current_state(TASK_INTERRUPTIBLE);
247
 
        schedule_timeout(HZ);
248
 
 
249
 
#if 0
250
 
        status = miniport_set_pm_state(wnd, NdisDeviceStateD0);
251
 
        if (status)
252
 
                DBGTRACE1("setting power state to device %s returns %08X",
253
 
                          wnd->net_dev->name, status);
254
 
#endif
 
267
         * fail after boot */
 
268
        sleep_hz(HZ / 2);
255
269
        set_bit(HW_INITIALIZED, &wnd->hw_status);
256
 
        set_bit(HW_AVAILABLE, &wnd->hw_status);
257
270
        hangcheck_add(wnd);
258
 
        stats_timer_add(wnd);
 
271
        up(&wnd->ndis_comm_mutex);
 
272
        up(&wnd->tx_ring_mutex);
 
273
        /* the description about NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND is
 
274
         * misleading/confusing; we just ignore it */
 
275
        status = miniport_query_info(wnd, OID_PNP_CAPABILITIES,
 
276
                                     &pnp_capa, sizeof(pnp_capa));
 
277
        if (status == NDIS_STATUS_SUCCESS)
 
278
                wnd->pm_capa = TRUE;
 
279
        else
 
280
                wnd->pm_capa = FALSE;
 
281
        DBGTRACE1("%d", pnp_capa.wakeup_capa.min_magic_packet_wakeup);
259
282
        TRACEEXIT1(return NDIS_STATUS_SUCCESS);
260
283
}
261
284
 
 
285
/* MiniportHalt */
262
286
static void miniport_halt(struct wrap_ndis_device *wnd)
263
287
{
264
288
        struct miniport_char *miniport;
265
289
 
266
290
        TRACEENTER1("%p", wnd);
267
 
        clear_bit(HW_AVAILABLE, &wnd->hw_status);
268
 
        hangcheck_del(wnd);
269
 
        stats_timer_del(wnd);
270
 
        if (!test_bit(HW_INITIALIZED, &wnd->hw_status)) {
 
291
        /* semaphores may already be locked, e.g., during suspend or
 
292
         * if device is suspended, but resume failed */
 
293
        down_trylock(&wnd->ndis_comm_mutex);
 
294
        down_trylock(&wnd->tx_ring_mutex);
 
295
        if (test_bit(HW_INITIALIZED, &wnd->hw_status)) {
 
296
                hangcheck_del(wnd);
 
297
                del_stats_timer(wnd);
 
298
                miniport = &wnd->wd->driver->ndis_driver->miniport;
 
299
                DBGTRACE1("halt: %p", miniport->miniport_halt);
 
300
                LIN2WIN1(miniport->miniport_halt, wnd->nmb->adapter_ctx);
 
301
                clear_bit(HW_INITIALIZED, &wnd->hw_status);
 
302
        } else
271
303
                WARNING("device %p is not initialized - not halting", wnd);
272
 
                TRACEEXIT1(return);
273
 
        }
274
 
        miniport = &wnd->wd->driver->ndis_driver->miniport;
275
 
        DBGTRACE1("driver halt is at %p", miniport->miniport_halt);
276
 
 
277
 
        DBGTRACE2("task: %p, pid: %d", get_current(), get_current()->pid);
278
 
        LIN2WIN1(miniport->miniport_halt, wnd->nmb->adapter_ctx);
279
 
        clear_bit(HW_INITIALIZED, &wnd->hw_status);
280
 
 
281
304
        TRACEEXIT1(return);
282
305
}
283
306
 
284
 
static NDIS_STATUS miniport_pnp_event(struct wrap_ndis_device *wnd,
285
 
                                      enum ndis_device_pnp_event event)
 
307
static NDIS_STATUS miniport_set_power_state(struct wrap_ndis_device *wnd,
 
308
                                            enum ndis_power_state state)
286
309
{
287
 
        struct miniport_char *miniport;
288
 
        ULONG pnp_info;
 
310
        NDIS_STATUS status;
289
311
 
290
 
        miniport = &wnd->wd->driver->ndis_driver->miniport;
291
 
        switch (event) {
292
 
        case NdisDevicePnPEventSurpriseRemoved:
293
 
                DBGTRACE1("%d, %p",
294
 
                          test_bit(ATTR_SURPRISE_REMOVE, &wnd->attributes),
295
 
                          miniport->pnp_event_notify);
296
 
                if (test_bit(ATTR_SURPRISE_REMOVE, &wnd->attributes) &&
297
 
                    miniport->pnp_event_notify) {
298
 
                        DBGTRACE1("calling surprise_removed");
299
 
                        LIN2WIN4(miniport->pnp_event_notify,
300
 
                                 wnd->nmb->adapter_ctx,
301
 
                                 NdisDevicePnPEventSurpriseRemoved, NULL, 0);
 
312
        DBGTRACE1("%d", state);
 
313
        if (state == NdisDeviceStateD0) {
 
314
                status = NDIS_STATUS_SUCCESS;
 
315
                if (test_and_clear_bit(HW_HALTED, &wnd->hw_status)) {
 
316
                        status = miniport_init(wnd);
 
317
                        if (status == NDIS_STATUS_SUCCESS) {
 
318
                                set_packet_filter(wnd, wnd->packet_filter);
 
319
                                set_multicast_list(wnd);
 
320
                        }
 
321
                } else if (test_and_clear_bit(HW_SUSPENDED, &wnd->hw_status)) {
 
322
                        up(&wnd->ndis_comm_mutex);
 
323
                        status = miniport_set_int(wnd, OID_PNP_SET_POWER,
 
324
                                                  state);
 
325
                        if (status == NDIS_STATUS_SUCCESS)
 
326
                                up(&wnd->tx_ring_mutex);
 
327
                        else {
 
328
                                down_interruptible(&wnd->ndis_comm_mutex);
 
329
                                WARNING("%s: setting power to state %d failed? "
 
330
                                        "%08X", wnd->net_dev->name, state,
 
331
                                        status);
 
332
                        }
 
333
                        if (wnd->ndis_wolopts &&
 
334
                            wrap_is_pci_bus(wnd->wd->dev_bus_type))
 
335
                                pci_enable_wake(wnd->wd->pci.pdev, PCI_D0, 0);
302
336
                } else
303
 
                        DBGTRACE1("Windows driver %s doesn't support "
304
 
                                  "MiniportPnpEventNotify for safe unplugging",
305
 
                                  wnd->wd->driver->name);
306
 
                return NDIS_STATUS_SUCCESS;
307
 
        case NdisDevicePnPEventPowerProfileChanged:
308
 
                if (!miniport->pnp_event_notify) {
309
 
                        DBGTRACE1("Windows driver %s doesn't support "
310
 
                                "MiniportPnpEventNotify",
311
 
                                  wnd->wd->driver->name);
312
337
                        return NDIS_STATUS_FAILURE;
313
 
                }
314
 
                pnp_info = NdisPowerProfileAcOnLine;
315
 
                DBGTRACE2("calling pnp_event_notify");
316
 
                LIN2WIN4(miniport->pnp_event_notify, wnd->nmb->adapter_ctx,
317
 
                         NdisDevicePnPEventPowerProfileChanged,
318
 
                         &pnp_info, (ULONG)sizeof(pnp_info));
319
 
                return NDIS_STATUS_SUCCESS;
320
 
        default:
321
 
                WARNING("event %d not yet implemented", event);
322
 
                return NDIS_STATUS_SUCCESS;
 
338
 
 
339
                if (status == NDIS_STATUS_SUCCESS) {
 
340
                        hangcheck_add(wnd);
 
341
                        add_stats_timer(wnd);
 
342
                        set_scan(wnd);
 
343
                        if (netif_running(wnd->net_dev)) {
 
344
                                netif_device_attach(wnd->net_dev);
 
345
                                netif_wake_queue(wnd->net_dev);
 
346
                        }
 
347
                        netif_poll_enable(wnd->net_dev);
 
348
                } else {
 
349
                        WARNING("%s: couldn't set power to state %d; device not"
 
350
                                " resumed", wnd->net_dev->name, state);
 
351
                }
 
352
                TRACEEXIT1(return status);
 
353
        } else {
 
354
                netif_poll_disable(wnd->net_dev);
 
355
                if (netif_running(wnd->net_dev)) {
 
356
                        netif_tx_disable(wnd->net_dev);
 
357
                        netif_device_detach(wnd->net_dev);
 
358
                }
 
359
                if (down_interruptible(&wnd->tx_ring_mutex))
 
360
                        WARNING("couldn't lock tx_ring_mutex");
 
361
                hangcheck_del(wnd);
 
362
                del_stats_timer(wnd);
 
363
                status = NDIS_STATUS_NOT_SUPPORTED;
 
364
                if (wnd->pm_capa == TRUE) {
 
365
                        enum ndis_power_state pm_state = state;
 
366
                        if (wnd->ndis_wolopts) {
 
367
                                status = miniport_set_int(wnd,
 
368
                                                          OID_PNP_ENABLE_WAKE_UP,
 
369
                                                          wnd->ndis_wolopts);
 
370
                                if (status == NDIS_STATUS_SUCCESS) {
 
371
                                        if (wrap_is_pci_bus(wnd->wd->dev_bus_type))
 
372
                                                pci_enable_wake(wnd->wd->pci.pdev,
 
373
                                                                PCI_D0, 1);
 
374
                                } else
 
375
                                        WARNING("%s: couldn't enable WOL: %08x",
 
376
                                                wnd->net_dev->name, status);
 
377
                        }
 
378
                        status = miniport_set_int(wnd, OID_PNP_SET_POWER,
 
379
                                                  pm_state);
 
380
                        if (status == NDIS_STATUS_SUCCESS) {
 
381
                                set_bit(HW_SUSPENDED, &wnd->hw_status);
 
382
                                if (down_interruptible(&wnd->ndis_comm_mutex))
 
383
                                        WARNING("couldn't lock ndis_comm_mutex");
 
384
                        } else
 
385
                                WARNING("suspend failed: %08X", status);
 
386
                }
 
387
                if (status != NDIS_STATUS_SUCCESS) {
 
388
                        WARNING("%s does not support power management; "
 
389
                                "halting the device", wnd->net_dev->name);
 
390
                        /* TODO: should we use pnp_stop_device instead? */
 
391
                        miniport_halt(wnd);
 
392
                        set_bit(HW_HALTED, &wnd->hw_status);
 
393
                        status = STATUS_SUCCESS;
 
394
                }
 
395
                TRACEEXIT1(return status);
323
396
        }
324
397
}
325
398
 
326
 
/*
327
 
 * query functions may not be called from this function as they might
328
 
 * sleep which is not allowed from the context this function is
329
 
 * running in.
330
 
 */
331
 
static struct net_device_stats *ndis_get_stats(struct net_device *dev)
332
 
{
333
 
        struct wrap_ndis_device *wnd = netdev_priv(dev);
334
 
        return &wnd->stats;
335
 
}
336
 
 
337
 
static int ndis_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
338
 
{
339
 
        int rc = -ENODEV;
340
 
        return rc;
341
 
}
342
 
 
343
 
/*
344
 
 * This function is called fom BH context
345
 
 */
346
 
static void ndis_set_multicast_list(struct net_device *dev)
347
 
{
348
 
        struct wrap_ndis_device *wnd = netdev_priv(dev);
349
 
        set_bit(SET_MULTICAST_LIST, &wnd->wrap_ndis_work);
350
 
        schedule_work(&wnd->wrap_ndis_worker);
351
 
}
352
 
 
353
399
static int ndis_set_mac_addr(struct net_device *dev, void *p)
354
400
{
355
401
        struct wrap_ndis_device *wnd = netdev_priv(dev);
367
413
        memset(mac_string, 0, sizeof(mac_string));
368
414
        res = snprintf(mac_string, sizeof(mac_string), MACSTR,
369
415
                       MAC2STR(mac));
370
 
        DBGTRACE2("res = %d, mac_tring = %s", res, mac_string);
371
416
        if (res != (sizeof(mac_string) - 1))
372
417
                TRACEEXIT1(return -EINVAL);
373
418
 
374
 
        ansi.buf = "mac_address";
375
 
        ansi.length = strlen(ansi.buf);
376
 
        ansi.max_length = ansi.length + 1;
 
419
        RtlInitAnsiString(&ansi, "mac_address");
377
420
        if (RtlAnsiStringToUnicodeString(&key, &ansi, TRUE))
378
421
                TRACEEXIT1(return -EINVAL);
379
422
 
380
 
        ansi.buf = mac_string;
381
 
        ansi.length = strlen(mac_string);
382
 
        ansi.max_length = ansi.length + 1;
383
 
        if (RtlAnsiStringToUnicodeString(&param.data.string, &ansi,
384
 
                                         TRUE) != NDIS_STATUS_SUCCESS) {
 
423
        RtlInitAnsiString(&ansi, mac_string);
 
424
        if (RtlAnsiStringToUnicodeString(&param.data.string, &ansi, TRUE)) {
385
425
                RtlFreeUnicodeString(&key);
386
426
                TRACEEXIT1(return -EINVAL);
387
427
        }
400
440
        TRACEEXIT1(return 0);
401
441
}
402
442
 
403
 
static void show_supported_oids(struct wrap_ndis_device *wnd)
404
 
{
405
 
        NDIS_STATUS res;
406
 
        int i, n, needed;
407
 
        ndis_oid *oids;
408
 
 
409
 
#ifndef DEBUG
410
 
        return;
411
 
#endif
412
 
        res = miniport_query_info_needed(wnd, OID_GEN_SUPPORTED_LIST, NULL, 0,
413
 
                                         &needed);
414
 
        if (!(res == NDIS_STATUS_BUFFER_TOO_SHORT ||
415
 
              res == NDIS_STATUS_INVALID_LENGTH))
416
 
                TRACEEXIT1(return);
417
 
        oids = kmalloc(needed, GFP_KERNEL);
418
 
        if (!oids) {
419
 
                DBGTRACE1("couldn't allocate memory");
420
 
                TRACEEXIT1(return);
421
 
        }
422
 
        res = miniport_query_info(wnd, OID_GEN_SUPPORTED_LIST, oids, needed);
423
 
        if (res) {
424
 
                DBGTRACE1("failed: %08X", res);
425
 
                kfree(oids);
426
 
                TRACEEXIT1(return);
427
 
        }
428
 
        for (i = 0, n = needed / sizeof(*oids); i < n; i++)
429
 
                DBGTRACE1("oid: %08X", oids[i]);
430
 
        kfree(oids);
431
 
        TRACEEXIT1(return);
432
 
}
433
 
 
434
 
static struct ndis_packet *
435
 
allocate_send_packet(struct wrap_ndis_device *wnd, ndis_buffer *buffer)
 
443
static struct ndis_packet *alloc_tx_packet(struct wrap_ndis_device *wnd,
 
444
                                           struct sk_buff *skb)
436
445
{
437
446
        struct ndis_packet *packet;
 
447
        ndis_buffer *buffer;
438
448
        struct ndis_packet_oob_data *oob_data;
439
449
        NDIS_STATUS status;
440
450
 
441
 
        NdisAllocatePacket(&status, &packet, wnd->wrapper_packet_pool);
 
451
        NdisAllocatePacket(&status, &packet, wnd->tx_packet_pool);
442
452
        if (status != NDIS_STATUS_SUCCESS)
443
453
                return NULL;
444
 
 
 
454
        NdisAllocateBuffer(&status, &buffer, wnd->tx_buffer_pool,
 
455
                           skb->data, skb->len);
 
456
        if (status != NDIS_STATUS_SUCCESS) {
 
457
                NdisFreePacket(packet);
 
458
                return NULL;
 
459
        }
445
460
        packet->private.buffer_head = buffer;
446
461
        packet->private.buffer_tail = buffer;
447
462
 
448
463
        oob_data = NDIS_PACKET_OOB_DATA(packet);
 
464
        oob_data->skb = skb;
449
465
        if (wnd->use_sg_dma) {
450
466
                oob_data->ndis_sg_element.address =
451
 
                        PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev,
452
 
                                           MmGetMdlVirtualAddress(buffer),
453
 
                                           MmGetMdlByteCount(buffer),
454
 
                                           PCI_DMA_TODEVICE);
455
 
 
456
 
                oob_data->ndis_sg_element.length = MmGetMdlByteCount(buffer);
 
467
                        PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, skb->data,
 
468
                                           skb->len, PCI_DMA_TODEVICE);
 
469
                oob_data->ndis_sg_element.length = skb->len;
457
470
                oob_data->ndis_sg_list.nent = 1;
458
471
                oob_data->ndis_sg_list.elements = &oob_data->ndis_sg_element;
459
472
                oob_data->extension.info[ScatterGatherListPacketInfo] =
460
473
                        &oob_data->ndis_sg_list;
461
474
        }
 
475
#if 0
 
476
        if (wnd->tx_csum_info.value)
 
477
                oob_data->extension.info[TcpIpChecksumPacketInfo] =
 
478
                        &wnd->tx_csum_info;
 
479
#endif
 
480
        DBG_BLOCK(4) {
 
481
                dump_bytes(__FUNCTION__, skb->data, skb->len);
 
482
        }
 
483
        DBGTRACE4("packet: %p, buffer: %p, skb: %p", packet, buffer, skb);
462
484
        return packet;
463
485
}
464
486
 
465
 
static void free_send_packet(struct wrap_ndis_device *wnd,
466
 
                             struct ndis_packet *packet)
 
487
void free_tx_packet(struct wrap_ndis_device *wnd, struct ndis_packet *packet,
 
488
                    NDIS_STATUS status)
467
489
{
468
490
        ndis_buffer *buffer;
469
491
        struct ndis_packet_oob_data *oob_data;
 
492
        KIRQL irql;
470
493
 
471
 
        TRACEENTER3("packet: %p", packet);
472
 
        if (!packet) {
473
 
                ERROR("illegal packet from %p", wnd);
474
 
                return;
 
494
        TRACEENTER3("%p, %08X", packet, status);
 
495
        irql = nt_spin_lock_irql(&wnd->tx_stats_lock, DISPATCH_LEVEL);
 
496
        if (status == NDIS_STATUS_SUCCESS) {
 
497
                wnd->stats.tx_bytes += packet->private.len;
 
498
                wnd->stats.tx_packets++;
 
499
        } else {
 
500
                DBGTRACE1("packet dropped: %08X", status);
 
501
                wnd->stats.tx_dropped++;
475
502
        }
476
 
 
477
 
        buffer = packet->private.buffer_head;
 
503
        nt_spin_unlock_irql(&wnd->tx_stats_lock, irql);
478
504
        oob_data = NDIS_PACKET_OOB_DATA(packet);
479
505
        if (wnd->use_sg_dma)
480
506
                PCI_DMA_UNMAP_SINGLE(wnd->wd->pci.pdev,
481
507
                                     oob_data->ndis_sg_element.address,
482
508
                                     oob_data->ndis_sg_element.length,
483
509
                                     PCI_DMA_TODEVICE);
484
 
 
 
510
        buffer = packet->private.buffer_head;
485
511
        DBGTRACE3("freeing buffer %p", buffer);
486
512
        NdisFreeBuffer(buffer);
487
 
        dev_kfree_skb(oob_data->skb);
488
 
 
 
513
        if (oob_data->skb)
 
514
                dev_kfree_skb_any(oob_data->skb);
489
515
        DBGTRACE3("freeing packet %p", packet);
490
516
        NdisFreePacket(packet);
491
517
        TRACEEXIT3(return);
492
518
}
493
519
 
494
 
/*
495
 
 * MiniportSend and MiniportSendPackets
496
 
 * this function is called with lock held in DISPATCH_LEVEL, so no need
497
 
 * to raise irql to DISPATCH_LEVEL during MiniportSend(Packets)
498
 
*/
499
 
static int send_packets(struct wrap_ndis_device *wnd, unsigned int start,
500
 
                        unsigned int pending)
 
520
/* MiniportSend and MiniportSendPackets */
 
521
/* this function is called holding tx_ring_mutex, so safe to read
 
522
 * tx_ring_start (tx_ring_end is not updated in tx_worker or here, so
 
523
 * safe to read tx_ring_end, too) without lock */
 
524
static int miniport_tx_packets(struct wrap_ndis_device *wnd)
501
525
{
502
526
        NDIS_STATUS res;
503
527
        struct miniport_char *miniport;
504
 
        unsigned int sent, n;
 
528
        int n, sent, start, end;
505
529
        struct ndis_packet *packet;
 
530
        KIRQL irql;
506
531
 
507
 
        TRACEENTER3("start: %d, pending: %d", start, pending);
508
532
        miniport = &wnd->wd->driver->ndis_driver->miniport;
509
 
        if (pending > wnd->max_send_packets)
510
 
                n = wnd->max_send_packets;
511
 
        else
512
 
                n = pending;
513
 
 
 
533
        start = wnd->tx_ring_start;
 
534
        end = wnd->tx_ring_end;
 
535
        /* end == start when ring is full: (TX_RING_SIZE - 1) number
 
536
         * of packets are pending */
 
537
        n = end - start;
 
538
        if (n < 0)
 
539
                n += TX_RING_SIZE;
 
540
        else if (n == 0) {
 
541
                assert(wnd->is_tx_ring_full == 1);
 
542
                n = TX_RING_SIZE - 1;
 
543
        }
 
544
        if (unlikely(n > wnd->max_tx_packets))
 
545
                n = wnd->max_tx_packets;
 
546
        DBGTRACE3("%d, %d, %d", n, start, end);
514
547
        if (miniport->send_packets) {
515
548
                int i;
516
 
                /* copy packets from xmit ring to linear xmit array */
 
549
                /* copy packets from tx ring to linear tx array */
517
550
                for (i = 0; i < n; i++) {
518
 
                        int j = (start + i) % XMIT_RING_SIZE;
519
 
                        wnd->xmit_array[i] = wnd->xmit_ring[j];
 
551
                        int j = (start + i) % TX_RING_SIZE;
 
552
                        wnd->tx_array[i] = wnd->tx_ring[j];
520
553
                }
521
 
                LIN2WIN3(miniport->send_packets, wnd->nmb->adapter_ctx,
522
 
                         wnd->xmit_array, n);
523
 
                DBGTRACE3("sent");
524
 
                if (test_bit(ATTR_SERIALIZED, &wnd->attributes)) {
525
 
                        for (sent = 0; sent < n && wnd->send_ok; sent++) {
526
 
                                struct ndis_packet_oob_data *oob_data;
527
 
                                packet = wnd->xmit_array[sent];
 
554
                if (wnd->attributes & NDIS_ATTRIBUTE_DESERIALIZE) {
 
555
                        LIN2WIN3(miniport->send_packets, wnd->nmb->adapter_ctx,
 
556
                                 wnd->tx_array, n);
 
557
                        sent = n;
 
558
                } else {
 
559
                        struct ndis_packet_oob_data *oob_data;
 
560
                        irql = raise_irql(DISPATCH_LEVEL);
 
561
                        LIN2WIN3(miniport->send_packets, wnd->nmb->adapter_ctx,
 
562
                                 wnd->tx_array, n);
 
563
                        lower_irql(irql);
 
564
                        for (sent = 0; sent < n && wnd->tx_ok; sent++) {
 
565
                                packet = wnd->tx_array[sent];
528
566
                                oob_data = NDIS_PACKET_OOB_DATA(packet);
529
 
                                switch(oob_data->status) {
 
567
                                switch (xchg(&oob_data->status,
 
568
                                             NDIS_STATUS_NOT_RECOGNIZED)) {
530
569
                                case NDIS_STATUS_SUCCESS:
531
 
                                        sendpacket_done(wnd, packet);
 
570
                                        free_tx_packet(wnd, packet,
 
571
                                                       NDIS_STATUS_SUCCESS);
532
572
                                        break;
533
573
                                case NDIS_STATUS_PENDING:
534
574
                                        break;
535
575
                                case NDIS_STATUS_RESOURCES:
536
 
                                        wnd->send_ok = 0;
 
576
                                        wnd->tx_ok = 0;
 
577
                                        /* resubmit this packet and
 
578
                                         * the rest when resources
 
579
                                         * become available */
 
580
                                        sent--;
537
581
                                        break;
538
582
                                case NDIS_STATUS_FAILURE:
 
583
                                        free_tx_packet(wnd, packet,
 
584
                                                       NDIS_STATUS_FAILURE);
 
585
                                        break;
539
586
                                default:
540
 
                                        free_send_packet(wnd, packet);
 
587
                                        ERROR("packet %p: invalid status",
 
588
                                              packet);
 
589
                                        free_tx_packet(wnd, packet,
 
590
                                                       oob_data->status);
541
591
                                        break;
542
592
                                }
543
593
                        }
544
 
                } else {
545
 
                        sent = n;
546
594
                }
 
595
                DBGTRACE3("sent: %d(%d)", sent, n);
547
596
        } else {
548
 
                packet = wnd->xmit_ring[start];
549
 
                res = LIN2WIN3(miniport->send, wnd->nmb->adapter_ctx,
550
 
                               packet, 0);
551
 
                sent = 1;
552
 
                switch (res) {
553
 
                case NDIS_STATUS_SUCCESS:
554
 
                        sendpacket_done(wnd, packet);
555
 
                        break;
556
 
                case NDIS_STATUS_PENDING:
557
 
                        break;
558
 
                case NDIS_STATUS_RESOURCES:
559
 
                        wnd->send_ok = 0;
560
 
                        sent = 0;
561
 
                        break;
562
 
                case NDIS_STATUS_FAILURE:
563
 
                        free_send_packet(wnd, packet);
564
 
                        break;
 
597
                int i;
 
598
                irql = PASSIVE_LEVEL;
 
599
                for (i = 0; i < n && wnd->tx_ok; i++) {
 
600
                        struct ndis_packet_oob_data *oob_data;
 
601
                        packet = wnd->tx_ring[(start + i) % TX_RING_SIZE];
 
602
                        oob_data = NDIS_PACKET_OOB_DATA(packet);
 
603
                        oob_data->status = NDIS_STATUS_NOT_RECOGNIZED;
 
604
                        if (!(wnd->attributes & NDIS_ATTRIBUTE_DESERIALIZE))
 
605
                                irql = raise_irql(DISPATCH_LEVEL);
 
606
                        res = LIN2WIN3(miniport->send, wnd->nmb->adapter_ctx,
 
607
                                       packet, packet->private.flags);
 
608
                        if (!(wnd->attributes & NDIS_ATTRIBUTE_DESERIALIZE))
 
609
                                lower_irql(irql);
 
610
                        switch (res) {
 
611
                        case NDIS_STATUS_SUCCESS:
 
612
                                free_tx_packet(wnd, packet, res);
 
613
                                break;
 
614
                        case NDIS_STATUS_PENDING:
 
615
                                break;
 
616
                        case NDIS_STATUS_RESOURCES:
 
617
                                wnd->tx_ok = 0;
 
618
                                /* resend this packet when resources
 
619
                                 * become available */
 
620
                                i--;
 
621
                                break;
 
622
                        case NDIS_STATUS_FAILURE:
 
623
                                free_tx_packet(wnd, packet, res);
 
624
                                break;
 
625
                        default:
 
626
                                ERROR("packet %p: invalid status: %08X",
 
627
                                      packet, res);
 
628
                                break;
 
629
                        }
565
630
                }
 
631
                sent = i + 1;
566
632
        }
567
633
        TRACEEXIT3(return sent);
568
634
}
569
635
 
570
 
static void xmit_worker(void *param)
 
636
static void tx_worker(void *param)
571
637
{
572
638
        struct wrap_ndis_device *wnd = (struct wrap_ndis_device *)param;
573
639
        int n;
574
 
        KIRQL irql;
575
 
 
576
 
        TRACEENTER3("send_ok %d", wnd->send_ok);
577
 
 
578
 
        /* some drivers e.g., new RT2500 driver, crash if any packets
579
 
         * are sent when the card is not associated */
580
 
        irql = kspin_lock_irql(&wnd->xmit_lock, DISPATCH_LEVEL);
581
 
        while (wnd->send_ok) {
582
 
                if (wnd->xmit_ring_pending == 0)
583
 
                        break;
584
 
                n = send_packets(wnd, wnd->xmit_ring_start,
585
 
                                 wnd->xmit_ring_pending);
586
 
                wnd->xmit_ring_start =
587
 
                        (wnd->xmit_ring_start + n) % XMIT_RING_SIZE;
588
 
                wnd->xmit_ring_pending -= n;
589
 
                if (netif_queue_stopped(wnd->net_dev) && n > 0)
590
 
                        netif_wake_queue(wnd->net_dev);
 
640
 
 
641
        TRACEENTER3("tx_ok %d", wnd->tx_ok);
 
642
        while (wnd->tx_ok) {
 
643
                if (down_interruptible(&wnd->tx_ring_mutex))
 
644
                        break;
 
645
                /* end == start if either ring is empty or full; in
 
646
                 * the latter case is_tx_ring_full is set */
 
647
                if (wnd->tx_ring_end == wnd->tx_ring_start &&
 
648
                    !wnd->is_tx_ring_full) {
 
649
                        up(&wnd->tx_ring_mutex);
 
650
                        break;
 
651
                }
 
652
                n = miniport_tx_packets(wnd);
 
653
                if (n > 0) {
 
654
                        wnd->tx_ring_start =
 
655
                                (wnd->tx_ring_start + n) % TX_RING_SIZE;
 
656
                        wnd->is_tx_ring_full = 0;
 
657
                        if (netif_queue_stopped(wnd->net_dev))
 
658
                                netif_wake_queue(wnd->net_dev);
 
659
                }
 
660
                up(&wnd->tx_ring_mutex);
 
661
                DBGTRACE3("%d, %d, %d", n, wnd->tx_ring_start,
 
662
                          wnd->tx_ring_end);
591
663
        }
592
 
        kspin_unlock_irql(&wnd->xmit_lock, irql);
593
 
 
594
 
        TRACEEXIT3(return);
595
 
}
596
 
 
597
 
/*
598
 
 * Free and unmap packet created in xmit
599
 
 */
600
 
void sendpacket_done(struct wrap_ndis_device *wnd, struct ndis_packet *packet)
601
 
{
602
 
        KIRQL irql;
603
 
 
604
 
        TRACEENTER3("%p", packet);
605
 
        irql = kspin_lock_irql(&wnd->send_packet_done_lock, DISPATCH_LEVEL);
606
 
        wnd->stats.tx_bytes += packet->private.len;
607
 
        wnd->stats.tx_packets++;
608
 
        free_send_packet(wnd, packet);
609
 
        kspin_unlock_irql(&wnd->send_packet_done_lock, irql);
610
 
        TRACEEXIT3(return);
611
 
}
612
 
 
613
 
/*
614
 
 * This function is called in BH disabled context and ndis drivers
615
 
 * must have their send-functions called from sleepeable context so we
616
 
 * just queue the packets up here and schedule a workqueue to run
617
 
 * later.
618
 
 */
619
 
static int start_xmit(struct sk_buff *skb, struct net_device *dev)
 
664
        TRACEEXIT3(return);
 
665
}
 
666
 
 
667
static int tx_skbuff(struct sk_buff *skb, struct net_device *dev)
620
668
{
621
669
        struct wrap_ndis_device *wnd = netdev_priv(dev);
622
 
        ndis_buffer *buffer;
623
670
        struct ndis_packet *packet;
624
 
        struct ndis_packet_oob_data *oob_data;
625
 
        unsigned int xmit_ring_next_slot;
626
 
        NDIS_STATUS res;
627
671
 
628
 
        NdisAllocateBuffer(&res, &buffer, wnd->wrapper_buffer_pool,
629
 
                           skb->data, skb->len);
630
 
        if (res != NDIS_STATUS_SUCCESS)
631
 
                return 1;
632
 
        packet = allocate_send_packet(wnd, buffer);
 
672
        packet = alloc_tx_packet(wnd, skb);
633
673
        if (!packet) {
634
 
                NdisFreeBuffer(buffer);
635
 
                return 1;
 
674
                WARNING("couldn't allocate packet");
 
675
                return NETDEV_TX_BUSY;
636
676
        }
637
 
        oob_data = NDIS_PACKET_OOB_DATA(packet);
638
 
        oob_data->skb = skb;
639
 
        kspin_lock(&wnd->xmit_lock);
640
 
        xmit_ring_next_slot = (wnd->xmit_ring_start +
641
 
                               wnd->xmit_ring_pending) % XMIT_RING_SIZE;
642
 
        wnd->xmit_ring[xmit_ring_next_slot] = packet;
643
 
        wnd->xmit_ring_pending++;
644
 
        if (wnd->xmit_ring_pending == XMIT_RING_SIZE)
 
677
        /* no need for lock here - already called holding
 
678
         * net_dev->xmit_lock and tx_ring_end is not updated
 
679
         * elsewhere */
 
680
        wnd->tx_ring[wnd->tx_ring_end++] = packet;
 
681
        if (wnd->tx_ring_end == TX_RING_SIZE)
 
682
                wnd->tx_ring_end = 0;
 
683
        if (wnd->tx_ring_end == wnd->tx_ring_start) {
 
684
                wnd->is_tx_ring_full = 1;
645
685
                netif_stop_queue(wnd->net_dev);
646
 
        kspin_unlock(&wnd->xmit_lock);
647
 
 
648
 
        schedule_work(&wnd->xmit_work);
649
 
 
650
 
        return 0;
 
686
        }
 
687
        DBGTRACE3("%d, %d", wnd->tx_ring_start, wnd->tx_ring_end);
 
688
        schedule_wrap_work(&wnd->tx_work);
 
689
        return NETDEV_TX_OK;
651
690
}
652
691
 
653
692
static int set_packet_filter(struct wrap_ndis_device *wnd, ULONG packet_filter)
654
693
{
655
694
        NDIS_STATUS res;
656
 
        ULONG filter = packet_filter;
657
695
 
658
 
        TRACEENTER3("%x", packet_filter);
659
 
        res = miniport_set_info(wnd, OID_GEN_CURRENT_PACKET_FILTER,
660
 
                                &filter, sizeof(filter));
661
 
        if (res) {
662
 
                DBGTRACE1("couldn't set packet filter: %08X", res);
663
 
                TRACEEXIT3(return res);
 
696
        while (1) {
 
697
                res = miniport_set_int(wnd, OID_GEN_CURRENT_PACKET_FILTER,
 
698
                                       packet_filter);
 
699
                if (res == NDIS_STATUS_SUCCESS)
 
700
                        break;
 
701
                DBGTRACE2("couldn't set filter 0x%08x", packet_filter);
 
702
                /* NDIS_PACKET_TYPE_PROMISCUOUS may not work with 802.11 */
 
703
                if (packet_filter & NDIS_PACKET_TYPE_PROMISCUOUS) {
 
704
                        packet_filter &= ~NDIS_PACKET_TYPE_PROMISCUOUS;
 
705
                        continue;
 
706
                }
 
707
                if (packet_filter & NDIS_PACKET_TYPE_ALL_LOCAL) {
 
708
                        packet_filter &= ~NDIS_PACKET_TYPE_ALL_LOCAL;
 
709
                        continue;
 
710
                }
 
711
                if (packet_filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) {
 
712
                        packet_filter &= ~NDIS_PACKET_TYPE_ALL_FUNCTIONAL;
 
713
                        continue;
 
714
                }
 
715
                if (packet_filter & NDIS_PACKET_TYPE_MULTICAST) {
 
716
                        packet_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
 
717
                        packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
 
718
                        continue;
 
719
                }
 
720
                if (packet_filter & NDIS_PACKET_TYPE_ALL_MULTICAST) {
 
721
                        packet_filter &= ~NDIS_PACKET_TYPE_ALL_MULTICAST;
 
722
                        continue;
 
723
                }
 
724
                break;
664
725
        }
 
726
 
665
727
        wnd->packet_filter = packet_filter;
666
 
        TRACEEXIT3(return 0);
667
 
}
668
 
 
669
 
static int get_packet_filter(struct wrap_ndis_device *wnd,
670
 
                             ULONG *packet_filter)
671
 
{
672
 
        NDIS_STATUS res;
673
 
 
674
 
        TRACEENTER3("%p", wnd);
675
 
        res = miniport_query_info(wnd, OID_GEN_CURRENT_PACKET_FILTER,
676
 
                                  packet_filter, sizeof(*packet_filter));
677
 
        if (res) {
678
 
                DBGTRACE1("couldn't get packet filter: %08X", res);
679
 
                TRACEEXIT3(return res);
 
728
        res = miniport_query_int(wnd, OID_GEN_CURRENT_PACKET_FILTER,
 
729
                                 &packet_filter);
 
730
        if (packet_filter != wnd->packet_filter) {
 
731
                WARNING("filter not set: 0x%08x, 0x%08x",
 
732
                        packet_filter, wnd->packet_filter);
 
733
                wnd->packet_filter = packet_filter;
680
734
        }
681
 
        TRACEEXIT3(return 0);
 
735
        if (wnd->packet_filter)
 
736
                TRACEEXIT3(return 0);
 
737
        else
 
738
                TRACEEXIT3(return -1);
682
739
}
683
740
 
684
741
static int ndis_open(struct net_device *dev)
687
744
        struct wrap_ndis_device *wnd = netdev_priv(dev);
688
745
 
689
746
        TRACEENTER1("%p", wnd);
690
 
        packet_filter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST;
691
 
        /* add any dev specific filters */
692
 
        if (dev->flags & IFF_PROMISC)
693
 
                packet_filter |= NDIS_PACKET_TYPE_PROMISCUOUS |
694
 
                        NDIS_PACKET_TYPE_ALL_LOCAL;
695
 
        if (set_packet_filter(wnd, packet_filter) && 
696
 
            packet_filter & NDIS_PACKET_TYPE_PROMISCUOUS) {
697
 
                DBGTRACE1("couldn't add packet filter %x", packet_filter);
698
 
                packet_filter &= ~NDIS_PACKET_TYPE_PROMISCUOUS;
699
 
                if (set_packet_filter(wnd, packet_filter))
700
 
                        DBGTRACE1("couldn't add packet filter %x",
701
 
                                  packet_filter);
 
747
        packet_filter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST |
 
748
                NDIS_PACKET_TYPE_ALL_FUNCTIONAL;
 
749
        if (set_packet_filter(wnd, packet_filter)) {
 
750
                WARNING("couldn't set packet filter");
 
751
                return -ENODEV;
702
752
        }
703
 
        /* NDIS_PACKET_TYPE_PROMISCUOUS will not work with 802.11 */
704
753
        netif_device_attach(dev);
705
754
        netif_start_queue(dev);
706
755
        return 0;
715
764
        return 0;
716
765
}
717
766
 
 
767
#ifdef CONFIG_NET_POLL_CONTROLLER
 
768
static void ndis_poll_controller(struct net_device *dev)
 
769
{
 
770
        struct wrap_ndis_device *wnd = netdev_priv(dev);
 
771
 
 
772
        disable_irq(dev->irq);
 
773
        if (wnd->ndis_irq->req_isr)
 
774
                ndis_isr_shared(dev->irq, wnd, NULL);
 
775
        else
 
776
                ndis_isr_dynamic(dev->irq, wnd, NULL);
 
777
        enable_irq(dev->irq);
 
778
}
 
779
#endif
 
780
 
 
781
/* this function is called fom BH context */
 
782
static struct net_device_stats *ndis_get_stats(struct net_device *dev)
 
783
{
 
784
        struct wrap_ndis_device *wnd = netdev_priv(dev);
 
785
        return &wnd->stats;
 
786
}
 
787
 
 
788
/* this function is called fom BH context */
 
789
static void ndis_set_multicast_list(struct net_device *dev)
 
790
{
 
791
        struct wrap_ndis_device *wnd = netdev_priv(dev);
 
792
        set_bit(SET_MULTICAST_LIST, &wnd->wrap_ndis_pending_work);
 
793
        schedule_wrap_work(&wnd->wrap_ndis_work);
 
794
}
 
795
 
 
796
/* this function is called fom BH context */
 
797
struct iw_statistics *get_wireless_stats(struct net_device *dev)
 
798
{
 
799
        struct wrap_ndis_device *wnd = netdev_priv(dev);
 
800
        return &wnd->wireless_stats;
 
801
}
 
802
 
 
803
#if defined(HAVE_ETHTOOL)
 
804
static void ndis_get_drvinfo(struct net_device *dev,
 
805
                             struct ethtool_drvinfo *info)
 
806
{
 
807
        struct wrap_ndis_device *wnd = netdev_priv(dev);
 
808
        strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
 
809
        strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
 
810
        strncpy(info->fw_version, wnd->wd->driver->version,
 
811
                sizeof(info->fw_version) - 1);
 
812
        if (wrap_is_pci_bus(wnd->wd->dev_bus_type))
 
813
                strncpy(info->bus_info, pci_name(wnd->wd->pci.pdev),
 
814
                        sizeof(info->bus_info) - 1);
 
815
#ifdef CONFIG_USB
 
816
        else
 
817
                usb_make_path(wnd->wd->usb.udev, info->bus_info,
 
818
                              sizeof(info->bus_info) - 1);
 
819
#endif
 
820
        return;
 
821
}
 
822
 
 
823
static u32 ndis_get_link(struct net_device *dev)
 
824
{
 
825
        struct wrap_ndis_device *wnd = netdev_priv(dev);
 
826
        return wnd->link_status;
 
827
}
 
828
 
 
829
static void ndis_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 
830
{
 
831
        struct wrap_ndis_device *wnd = netdev_priv(dev);
 
832
        if (wnd->ndis_wolopts & NDIS_PNP_WAKE_UP_MAGIC_PACKET)
 
833
                wol->wolopts |= WAKE_MAGIC;
 
834
        /* no other options supported */
 
835
        return;
 
836
}
 
837
 
 
838
static int ndis_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 
839
{
 
840
        struct wrap_ndis_device *wnd = netdev_priv(dev);
 
841
        struct ndis_pnp_capabilities pnp_capa;
 
842
        NDIS_STATUS status;
 
843
 
 
844
        if (!(wol->wolopts & WAKE_MAGIC))
 
845
                return -EINVAL;
 
846
        if (!wnd->pm_capa)
 
847
                return -EOPNOTSUPP;
 
848
        status = miniport_query_info(wnd, OID_PNP_CAPABILITIES,
 
849
                                     &pnp_capa, sizeof(pnp_capa));
 
850
        if (status != NDIS_STATUS_SUCCESS)
 
851
                return -EOPNOTSUPP;
 
852
        /* we always suspend to D3 */
 
853
        DBGTRACE1("%d, %d", pnp_capa.wakeup_capa.min_magic_packet_wakeup,
 
854
                  pnp_capa.wakeup_capa.min_pattern_wakeup);
 
855
        if (pnp_capa.wakeup_capa.min_magic_packet_wakeup != NdisDeviceStateD3)
 
856
                return -EOPNOTSUPP;
 
857
        /* no other options supported */
 
858
        wnd->ndis_wolopts = NDIS_PNP_WAKE_UP_MAGIC_PACKET;
 
859
        return 0;
 
860
}
 
861
 
 
862
static struct ethtool_ops ndis_ethtool_ops = {
 
863
        .get_drvinfo            = ndis_get_drvinfo,
 
864
        .get_link               = ndis_get_link,
 
865
        .get_wol                = ndis_get_wol,
 
866
        .set_wol                = ndis_set_wol,
 
867
};
 
868
#endif
 
869
 
718
870
static void update_wireless_stats(struct wrap_ndis_device *wnd)
719
871
{
720
872
        struct iw_statistics *iw_stats = &wnd->wireless_stats;
760
912
{
761
913
        struct net_device *net_dev;
762
914
        ULONG packet_filter;
763
 
        NDIS_STATUS res = 0;
 
915
        NDIS_STATUS res;
764
916
 
765
917
        net_dev = wnd->net_dev;
766
 
        if (!(net_dev->mc_count > 0 ||
767
 
              net_dev->flags & IFF_ALLMULTI))
768
 
                TRACEEXIT3(return);
 
918
        packet_filter = wnd->packet_filter;
769
919
 
770
 
        res = get_packet_filter(wnd, &packet_filter);
771
 
        if (res) {
772
 
//              WARNING("couldn't get packet filter: %08X", res);
773
 
                TRACEEXIT3(return);
 
920
        DBGTRACE2("0x%08x", packet_filter);
 
921
        if (net_dev->flags & IFF_PROMISC) {
 
922
                packet_filter |= NDIS_PACKET_TYPE_PROMISCUOUS |
 
923
                        NDIS_PACKET_TYPE_ALL_LOCAL;
 
924
        } else if (net_dev->flags & IFF_ALLMULTI ||
 
925
                   net_dev->mc_count > wnd->multicast_size) {
 
926
                packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
 
927
                DBGTRACE2("0x%08x", packet_filter);
 
928
        } else if (net_dev->mc_count > 0) {
 
929
                int i, size;
 
930
                char *buf;
 
931
                struct dev_mc_list *mclist;
 
932
                size = min(wnd->multicast_size, net_dev->mc_count);
 
933
                DBGTRACE2("%d, %d", wnd->multicast_size, net_dev->mc_count);
 
934
                buf = kmalloc(size * ETH_ALEN, GFP_KERNEL);
 
935
                if (!buf) {
 
936
                        WARNING("couldn't allocate memory");
 
937
                        TRACEEXIT2(return);
 
938
                }
 
939
                mclist = net_dev->mc_list;
 
940
                for (i = 0; i < size && mclist; mclist = mclist->next) {
 
941
                        if (mclist->dmi_addrlen != ETH_ALEN)
 
942
                                continue;
 
943
                        memcpy(buf + i * ETH_ALEN, mclist->dmi_addr, ETH_ALEN);
 
944
                        DBGTRACE2(MACSTR, MAC2STR(mclist->dmi_addr));
 
945
                        i++;
 
946
                }
 
947
                res = miniport_set_info(wnd, OID_802_3_MULTICAST_LIST,
 
948
                                        buf, i * ETH_ALEN);
 
949
                if (res == NDIS_STATUS_SUCCESS && i > 0)
 
950
                        packet_filter |= NDIS_PACKET_TYPE_MULTICAST;
 
951
                else
 
952
                        packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
 
953
                kfree(buf);
774
954
        }
775
 
 
776
 
        packet_filter |= NDIS_PACKET_TYPE_MULTICAST;
777
 
        packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
778
 
        DBGTRACE2("packet filter: %08x", packet_filter);
 
955
        DBGTRACE2("0x%08x", packet_filter);
779
956
        res = set_packet_filter(wnd, packet_filter);
780
957
        if (res)
781
958
                DBGTRACE1("couldn't set packet filter (%08X)", res);
782
 
 
783
959
        TRACEEXIT2(return);
784
960
}
785
961
 
786
962
static void link_status_handler(struct wrap_ndis_device *wnd)
787
963
{
788
964
        struct ndis_assoc_info *ndis_assoc_info;
789
 
#if WIRELESS_EXT < 18
 
965
        union iwreq_data wrqu;
 
966
        NDIS_STATUS res;
 
967
        const int assoc_size = sizeof(*ndis_assoc_info) + IW_CUSTOM_MAX + 32;
 
968
#if WIRELESS_EXT <= 17
790
969
        unsigned char *wpa_assoc_info, *ies;
791
970
        unsigned char *p;
792
971
        int i;
793
972
#endif
794
 
        unsigned char *assoc_info;
795
 
        union iwreq_data wrqu;
796
 
        NDIS_STATUS res;
797
 
        const int assoc_size = sizeof(*ndis_assoc_info) + IW_CUSTOM_MAX;
798
973
 
799
 
        TRACEENTER2("link status: %d", wnd->link_status);
 
974
        TRACEENTER2("link: %d", wnd->link_status);
 
975
        if (wnd->physical_medium != NdisPhysicalMediumWirelessLan)
 
976
                TRACEEXIT2(return);
800
977
        if (wnd->link_status == 0) {
801
 
#if 0
802
 
                unsigned int i;
803
 
                struct encr_info *encr_info = &wnd->encr_info;
804
 
 
805
 
                if (wnd->encr_mode == Ndis802_11Encryption1Enabled ||
806
 
                    wnd->infrastructure_mode == Ndis802_11IBSS) {
807
 
                        for (i = 0; i < MAX_ENCR_KEYS; i++) {
808
 
                                if (encr_info->keys[i].length == 0)
809
 
                                        continue;
810
 
                                add_wep_key(wnd, encr_info->keys[i].key,
811
 
                                            encr_info->keys[i].length, i);
812
 
                        }
813
 
 
814
 
                        set_bit(SET_ESSID, &wnd->wrap_ndis_work);
815
 
                        schedule_work(&wnd->wrap_ndis_worker);
816
 
                        TRACEEXIT2(return);
817
 
                }
818
 
                /* TODO: not clear if NDIS says keys should
819
 
                 * be cleared here */
820
 
                for (i = 0; i < MAX_ENCR_KEYS; i++)
821
 
                        wnd->encr_info.keys[i].length = 0;
822
 
#endif
823
 
 
 
978
                wnd->tx_ok = 0;
824
979
                memset(&wrqu, 0, sizeof(wrqu));
825
980
                wrqu.ap_addr.sa_family = ARPHRD_ETHER;
826
981
                wireless_send_event(wnd->net_dev, SIOCGIWAP, &wrqu, NULL);
827
982
                TRACEEXIT2(return);
828
983
        }
829
984
 
830
 
        if (!(test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr) ||
831
 
              test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr)))
832
 
                TRACEEXIT2(return);
833
 
 
834
 
        assoc_info = kmalloc(assoc_size, GFP_KERNEL);
835
 
        if (!assoc_info) {
 
985
        wnd->tx_ok = 1;
 
986
        ndis_assoc_info = kmalloc(assoc_size, GFP_KERNEL);
 
987
        if (!ndis_assoc_info) {
836
988
                ERROR("couldn't allocate memory");
837
989
                TRACEEXIT2(return);
838
990
        }
839
 
        memset(assoc_info, 0, assoc_size);
 
991
        memset(ndis_assoc_info, 0, assoc_size);
840
992
 
841
 
        ndis_assoc_info = (struct ndis_assoc_info *)assoc_info;
842
 
#if 0
843
 
        ndis_assoc_info->length = sizeof(*ndis_assoc_info);
844
 
        ndis_assoc_info->offset_req_ies = sizeof(*ndis_assoc_info);
845
 
        ndis_assoc_info->req_ie_length = IW_CUSTOM_MAX / 2;
846
 
        ndis_assoc_info->offset_resp_ies = sizeof(*ndis_assoc_info) +
847
 
                ndis_assoc_info->req_ie_length;
848
 
        ndis_assoc_info->resp_ie_length = IW_CUSTOM_MAX / 2;
849
 
#endif
850
993
        res = miniport_query_info(wnd, OID_802_11_ASSOCIATION_INFORMATION,
851
 
                                  assoc_info, assoc_size);
 
994
                                  ndis_assoc_info, assoc_size);
852
995
        if (res) {
853
996
                DBGTRACE2("query assoc_info failed (%08X)", res);
854
 
                kfree(assoc_info);
 
997
                kfree(ndis_assoc_info);
855
998
                TRACEEXIT2(return);
856
999
        }
857
1000
 
858
 
        /*
859
 
         * TODO: backwards compatibility would require that IWEVCUSTOM
860
 
         * is sent even if WIRELESS_EXT > 17. This version does not do
861
 
         * this in order to allow wpa_supplicant to be tested with
862
 
         * WE-18.
863
 
         */
864
1001
#if WIRELESS_EXT > 17
865
1002
        memset(&wrqu, 0, sizeof(wrqu));
866
1003
        wrqu.data.length = ndis_assoc_info->req_ie_length;
867
1004
        wireless_send_event(wnd->net_dev, IWEVASSOCREQIE, &wrqu,
868
 
                            ((char *) ndis_assoc_info) +
 
1005
                            ((char *)ndis_assoc_info) +
869
1006
                            ndis_assoc_info->offset_req_ies);
870
1007
        wrqu.data.length = ndis_assoc_info->resp_ie_length;
871
1008
        wireless_send_event(wnd->net_dev, IWEVASSOCRESPIE, &wrqu,
872
 
                            ((char *) ndis_assoc_info) +
 
1009
                            ((char *)ndis_assoc_info) +
873
1010
                            ndis_assoc_info->offset_resp_ies);
874
1011
#else
875
1012
        /* we need 28 extra bytes for the format strings */
879
1016
                        "association information dropped",
880
1017
                        ndis_assoc_info->req_ie_length,
881
1018
                        ndis_assoc_info->resp_ie_length);
882
 
                kfree(assoc_info);
 
1019
                kfree(ndis_assoc_info);
883
1020
                TRACEEXIT2(return);
884
1021
        }
885
1022
 
886
1023
        wpa_assoc_info = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
887
1024
        if (!wpa_assoc_info) {
888
1025
                ERROR("couldn't allocate memory");
889
 
                kfree(assoc_info);
 
1026
                kfree(ndis_assoc_info);
890
1027
                TRACEEXIT2(return);
891
1028
        }
892
1029
        p = wpa_assoc_info;
893
1030
        p += sprintf(p, "ASSOCINFO(ReqIEs=");
894
 
        ies = ((char *)ndis_assoc_info) +
895
 
                ndis_assoc_info->offset_req_ies;
 
1031
        ies = ((char *)ndis_assoc_info) + ndis_assoc_info->offset_req_ies;
896
1032
        for (i = 0; i < ndis_assoc_info->req_ie_length; i++)
897
1033
                p += sprintf(p, "%02x", ies[i]);
898
1034
 
899
1035
        p += sprintf(p, " RespIEs=");
900
 
        ies = ((char *)ndis_assoc_info) +
901
 
                ndis_assoc_info->offset_resp_ies;
 
1036
        ies = ((char *)ndis_assoc_info) + ndis_assoc_info->offset_resp_ies;
902
1037
        for (i = 0; i < ndis_assoc_info->resp_ie_length; i++)
903
1038
                p += sprintf(p, "%02x", ies[i]);
904
1039
 
906
1041
 
907
1042
        memset(&wrqu, 0, sizeof(wrqu));
908
1043
        wrqu.data.length = p - wpa_assoc_info;
909
 
        DBGTRACE2("adding %d bytes", wrqu.data.length);
910
1044
        wireless_send_event(wnd->net_dev, IWEVCUSTOM, &wrqu, wpa_assoc_info);
911
1045
 
912
1046
        kfree(wpa_assoc_info);
913
1047
#endif
914
 
        kfree(assoc_info);
 
1048
        kfree(ndis_assoc_info);
915
1049
 
916
1050
        get_ap_address(wnd, (char *)&wrqu.ap_addr.sa_data);
917
1051
        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
918
1052
        wireless_send_event(wnd->net_dev, SIOCGIWAP, &wrqu, NULL);
919
 
        DBGTRACE2("associate to " MACSTR, MAC2STR(wrqu.ap_addr.sa_data));
 
1053
        DBGTRACE2(MACSTR, MAC2STR(wrqu.ap_addr.sa_data));
920
1054
        TRACEEXIT2(return);
921
1055
}
922
1056
 
923
 
static void stats_proc(unsigned long data)
 
1057
static void stats_timer_proc(unsigned long data)
924
1058
{
925
1059
        struct wrap_ndis_device *wnd = (struct wrap_ndis_device *)data;
926
1060
 
927
 
        set_bit(COLLECT_STATS, &wnd->wrap_ndis_work);
928
 
        schedule_work(&wnd->wrap_ndis_worker);
 
1061
        set_bit(COLLECT_STATS, &wnd->wrap_ndis_pending_work);
 
1062
        schedule_wrap_work(&wnd->wrap_ndis_work);
929
1063
        wnd->stats_timer.expires += 10 * HZ;
930
1064
        add_timer(&wnd->stats_timer);
931
1065
}
932
1066
 
933
 
static void stats_timer_add(struct wrap_ndis_device *wnd)
 
1067
static void add_stats_timer(struct wrap_ndis_device *wnd)
934
1068
{
935
1069
        init_timer(&wnd->stats_timer);
 
1070
        if (wnd->physical_medium != NdisPhysicalMediumWirelessLan)
 
1071
                return;
936
1072
        wnd->stats_timer.data = (unsigned long)wnd;
937
 
        wnd->stats_timer.function = &stats_proc;
 
1073
        wnd->stats_timer.function = &stats_timer_proc;
938
1074
        wnd->stats_timer.expires = jiffies + 10 * HZ;
939
1075
        add_timer(&wnd->stats_timer);
940
1076
}
941
1077
 
942
 
static void stats_timer_del(struct wrap_ndis_device *wnd)
 
1078
static void del_stats_timer(struct wrap_ndis_device *wnd)
943
1079
{
944
1080
        del_timer_sync(&wnd->stats_timer);
945
1081
}
949
1085
        struct wrap_ndis_device *wnd = (struct wrap_ndis_device *)data;
950
1086
 
951
1087
        TRACEENTER3("");
952
 
        if (wnd->hangcheck_interval <= 0)
953
 
                return;
954
 
 
955
 
        set_bit(HANGCHECK, &wnd->wrap_ndis_work);
956
 
        schedule_work(&wnd->wrap_ndis_worker);
 
1088
        set_bit(HANGCHECK, &wnd->wrap_ndis_pending_work);
 
1089
        schedule_wrap_work(&wnd->wrap_ndis_work);
957
1090
 
958
1091
        wnd->hangcheck_timer.expires += wnd->hangcheck_interval;
959
1092
        add_timer(&wnd->hangcheck_timer);
964
1097
void hangcheck_add(struct wrap_ndis_device *wnd)
965
1098
{
966
1099
        if (!wnd->wd->driver->ndis_driver->miniport.hangcheck ||
967
 
            wnd->hangcheck_interval <= 0)
 
1100
            hangcheck_interval < 0)
968
1101
                return;
 
1102
        if (hangcheck_interval > 0)
 
1103
                wnd->hangcheck_interval = hangcheck_interval * HZ;
969
1104
        init_timer(&wnd->hangcheck_timer);
970
1105
        wnd->hangcheck_timer.data = (unsigned long)wnd;
971
1106
        wnd->hangcheck_timer.function = &hangcheck_proc;
979
1114
        del_timer_sync(&wnd->hangcheck_timer);
980
1115
}
981
1116
 
982
 
#ifdef HAVE_ETHTOOL
983
 
static u32 ndis_get_link(struct net_device *dev)
984
 
{
985
 
        struct wrap_ndis_device *wnd = netdev_priv(dev);
986
 
        return wnd->link_status;
987
 
}
988
 
 
989
 
static struct ethtool_ops ndis_ethtool_ops = {
990
 
        .get_link               = ndis_get_link,
991
 
};
992
 
#endif
993
 
 
994
1117
/* worker procedure to take care of setting/checking various states */
995
 
static void wrap_ndis_worker_proc(void *param)
 
1118
static void wrap_ndis_worker(void *param)
996
1119
{
997
1120
        struct wrap_ndis_device *wnd = (struct wrap_ndis_device *)param;
998
1121
 
999
 
        DBGTRACE2("%lu", wnd->wrap_ndis_work);
 
1122
        DBGTRACE2("%lu", wnd->wrap_ndis_pending_work);
1000
1123
 
1001
 
        if (test_bit(SHUTDOWN, &wnd->wrap_ndis_work) ||
1002
 
            !test_bit(HW_INITIALIZED, &wnd->hw_status))
 
1124
        if (test_bit(SHUTDOWN, &wnd->wrap_ndis_pending_work))
1003
1125
                TRACEEXIT3(return);
1004
1126
 
1005
 
        if (test_and_clear_bit(SET_INFRA_MODE, &wnd->wrap_ndis_work))
1006
 
                set_infra_mode(wnd, wnd->infrastructure_mode);
1007
 
 
1008
 
        if (test_and_clear_bit(SET_ESSID, &wnd->wrap_ndis_work))
1009
 
                set_essid(wnd, wnd->essid.essid, wnd->essid.length);
1010
 
 
1011
 
        if (test_and_clear_bit(SET_MULTICAST_LIST, &wnd->wrap_ndis_work))
 
1127
        if (test_and_clear_bit(SET_MULTICAST_LIST, &wnd->wrap_ndis_pending_work))
1012
1128
                set_multicast_list(wnd);
1013
1129
 
1014
 
        if (test_and_clear_bit(COLLECT_STATS, &wnd->wrap_ndis_work))
 
1130
        if (test_and_clear_bit(COLLECT_STATS, &wnd->wrap_ndis_pending_work))
1015
1131
                update_wireless_stats(wnd);
1016
1132
 
1017
 
        if (test_and_clear_bit(LINK_STATUS_CHANGED, &wnd->wrap_ndis_work))
 
1133
        if (test_and_clear_bit(LINK_STATUS_CHANGED,
 
1134
                               &wnd->wrap_ndis_pending_work))
1018
1135
                link_status_handler(wnd);
1019
1136
 
1020
 
        if (test_and_clear_bit(HANGCHECK, &wnd->wrap_ndis_work)) {
 
1137
        if (test_and_clear_bit(HANGCHECK, &wnd->wrap_ndis_pending_work)) {
1021
1138
                NDIS_STATUS res;
1022
1139
                struct miniport_char *miniport;
1023
1140
                KIRQL irql;
1029
1146
                if (res) {
1030
1147
                        WARNING("%s is being reset", wnd->net_dev->name);
1031
1148
                        res = miniport_reset(wnd);
1032
 
                        DBGTRACE3("reset returns %08X", res);
 
1149
                        DBGTRACE3("%08X", res);
1033
1150
                }
1034
1151
        }
1035
1152
        TRACEEXIT3(return);
1036
1153
}
1037
1154
 
1038
 
struct iw_statistics *get_wireless_stats(struct net_device *dev)
1039
 
{
1040
 
        struct wrap_ndis_device *wnd = netdev_priv(dev);
1041
 
        return &wnd->wireless_stats;
1042
 
}
1043
 
 
1044
1155
NDIS_STATUS ndis_reinit(struct wrap_ndis_device *wnd)
1045
1156
{
1046
1157
        pnp_stop_device(wnd->wd);
1047
1158
        return pnp_start_device(wnd->wd);
1048
1159
}
1049
1160
 
1050
 
/* check capabilites - mainly for WPA */
1051
 
void check_capa(struct wrap_ndis_device *wnd)
 
1161
void get_encryption_capa(struct wrap_ndis_device *wnd)
1052
1162
{
1053
1163
        int i, mode;
1054
1164
        NDIS_STATUS res;
1105
1215
        ndis_key.struct_size = sizeof(ndis_key);
1106
1216
        res = miniport_set_info(wnd, OID_802_11_ADD_KEY, &ndis_key,
1107
1217
                                ndis_key.struct_size);
1108
 
        DBGTRACE2("add key returns %08X, size = %lu",
1109
 
                  res, (unsigned long)sizeof(ndis_key));
 
1218
        DBGTRACE2("%08X, %lu", res, (unsigned long)sizeof(ndis_key));
1110
1219
        if (res && res != NDIS_STATUS_INVALID_DATA)
1111
1220
                TRACEEXIT1(return);
1112
1221
        res = miniport_query_info(wnd, OID_802_11_ASSOCIATION_INFORMATION,
1113
1222
                                  &ndis_assoc_info, sizeof(ndis_assoc_info));
1114
 
        DBGTRACE1("assoc info returns %08X", res);
 
1223
        DBGTRACE1("%08X", res);
1115
1224
        if (res == NDIS_STATUS_NOT_SUPPORTED)
1116
1225
                TRACEEXIT1(return);
1117
1226
 
1133
1242
        c = (struct ndis_capability *)buf;
1134
1243
        res = miniport_query_info(wnd, OID_802_11_CAPABILITY, buf, buf_len);
1135
1244
        if (!(res == NDIS_STATUS_SUCCESS && c->version == 2)) {
1136
 
                DBGTRACE1("res: %X", res);
1137
1245
                kfree(buf);
1138
1246
                TRACEEXIT1(return);
1139
1247
        }
1175
1283
        TRACEEXIT1(return);
1176
1284
}
1177
1285
 
1178
 
static NDIS_STATUS miniport_set_power_state(struct wrap_ndis_device *wnd,
1179
 
                                            enum ndis_power_state state)
1180
 
{
1181
 
        NDIS_STATUS status;
1182
 
        struct miniport_char *miniport;
1183
 
 
1184
 
        TRACEENTER2("state: %d", state);
1185
 
        if (state == NdisDeviceStateD0) {
1186
 
                status = STATUS_SUCCESS;
1187
 
                if (test_and_clear_bit(HW_HALTED, &wnd->hw_status)) {
1188
 
                        DBGTRACE2("starting device");
1189
 
                        /* TODO: should we use pnp_start_device instead? */
1190
 
                        if (miniport_init(wnd) != NDIS_STATUS_SUCCESS) {
1191
 
                                WARNING("couldn't re-initialize device %s",
1192
 
                                        wnd->net_dev->name);
1193
 
                                TRACEEXIT2(return NDIS_STATUS_FAILURE);
1194
 
                        }
1195
 
                }
1196
 
                if (test_and_clear_bit(HW_SUSPENDED, &wnd->hw_status)) {
1197
 
                        status = miniport_set_int(wnd, OID_PNP_SET_POWER,
1198
 
                                                  NdisDeviceStateD0);
1199
 
                        DBGTRACE2("set_power returns %08X", status);
1200
 
                        miniport = &wnd->wd->driver->ndis_driver->miniport;
1201
 
                        if (status == NDIS_STATUS_SUCCESS)
1202
 
                                miniport_pnp_event(wnd,
1203
 
                                   NdisDevicePnPEventPowerProfileChanged);
1204
 
                }
1205
 
                TRACEEXIT1(return status);
1206
 
        } else {
1207
 
                status = miniport_set_int(wnd, OID_PNP_SET_POWER, state);
1208
 
                if (status == NDIS_STATUS_SUCCESS)
1209
 
                        set_bit(HW_SUSPENDED, &wnd->hw_status);
1210
 
                else
1211
 
                        WARNING("setting power state to %d failed: %08X",
1212
 
                                state, status);
1213
 
                if (status != NDIS_STATUS_SUCCESS) {
1214
 
                        WARNING("device may not support power management");
1215
 
                        DBGTRACE2("no pm: halting the device");
1216
 
                        /* TODO: should we use pnp_stop_device instead? */
1217
 
                        miniport_halt(wnd);
1218
 
                        set_bit(HW_HALTED, &wnd->hw_status);
1219
 
                        status = STATUS_SUCCESS;
1220
 
                }
1221
 
                TRACEEXIT1(return status);
1222
 
        }
1223
 
}
1224
 
 
1225
 
STDCALL NTSTATUS NdisDispatchDeviceControl(struct device_object *fdo,
1226
 
                                           struct irp *irp)
 
1286
/* called as Windows function, so call WIN2LIN2 before accessing
 
1287
 * arguments */
 
1288
wstdcall NTSTATUS NdisDispatchDeviceControl(struct device_object *fdo,
 
1289
                                            struct irp *irp)
1227
1290
{
1228
1291
        struct wrap_ndis_device *wnd;
 
1292
 
 
1293
        WIN2LIN2(fdo, irp);
 
1294
 
1229
1295
        DBGTRACE3("fdo: %p", fdo);
1230
1296
        /* for now, we don't have anything intresting here, so pass it
1231
1297
         * down to bus driver */
1232
1298
        wnd = fdo->reserved;
1233
 
        return IopPassIrpDown(wnd->nmb->pdo, irp);
 
1299
        return LIN2WIN2(IoPassIrpDown, wnd->nmb->pdo, irp);
1234
1300
}
1235
1301
 
1236
 
STDCALL NTSTATUS NdisDispatchPower(struct device_object *fdo,
1237
 
                                   struct irp *irp)
 
1302
/* called as Windows function, so call WIN2LIN2 before accessing
 
1303
 * arguments */
 
1304
wstdcall NTSTATUS NdisDispatchPower(struct device_object *fdo, struct irp *irp)
1238
1305
{
1239
1306
        struct io_stack_location *irp_sl;
1240
1307
        struct wrap_ndis_device *wnd;
1242
1309
        NTSTATUS status;
1243
1310
        NDIS_STATUS ndis_status;
1244
1311
 
 
1312
        WIN2LIN2(fdo, irp);
 
1313
 
1245
1314
        irp_sl = IoGetCurrentIrpStackLocation(irp);
1246
1315
        wnd = fdo->reserved;
1247
1316
        IOTRACE("fdo: %p, fn: %d:%d, wnd: %p", fdo, irp_sl->major_fn,
1248
1317
                irp_sl->minor_fn, wnd);
1249
 
        if (irp_sl->params.power.state.device_state == PowerDeviceD0)
 
1318
        if ((irp_sl->params.power.type == SystemPowerState &&
 
1319
             irp_sl->params.power.state.system_state > PowerSystemWorking) ||
 
1320
            (irp_sl->params.power.type == DevicePowerState &&
 
1321
             irp_sl->params.power.state.device_state > PowerDeviceD0))
 
1322
                state = NdisDeviceStateD3;
 
1323
        else
1250
1324
                state = NdisDeviceStateD0;
1251
 
        else
1252
 
                state = NdisDeviceStateD3;
1253
1325
        switch (irp_sl->minor_fn) {
1254
1326
        case IRP_MN_SET_POWER:
1255
1327
                if (state == NdisDeviceStateD0) {
1256
 
                        IoCopyCurrentIrpStackLocationToNext(irp);
1257
 
                        IoSetCompletionRoutine(irp, IrpStopCompletion, wnd,
1258
 
                                               TRUE, FALSE, FALSE);
1259
 
                        status = IoCallDriver(wnd->nmb->pdo, irp);
 
1328
                        status = LIN2WIN2(IoSyncForwardIrp, wnd->nmb->pdo, irp);
1260
1329
                        if (status != STATUS_SUCCESS)
1261
 
                                return status;
 
1330
                                break;
1262
1331
                        ndis_status = miniport_set_power_state(wnd, state);
1263
1332
                        if (ndis_status != NDIS_STATUS_SUCCESS)
1264
 
                                WARNING("setting power to %d failed: %08X",
 
1333
                                WARNING("couldn't set power to %d: %08X",
1265
1334
                                        state, ndis_status);
1266
 
                        hangcheck_add(wnd);
1267
 
                        stats_timer_add(wnd);
1268
 
                        set_scan(wnd);
1269
 
                        set_bit(SET_ESSID, &wnd->wrap_ndis_work);
1270
 
                        if (netif_running(wnd->net_dev)) {
1271
 
                                netif_device_attach(wnd->net_dev);
1272
 
                                netif_wake_queue(wnd->net_dev);
1273
 
                        }
1274
 
                        netif_poll_enable(wnd->net_dev);
1275
1335
                        DBGTRACE2("%s: device resumed", wnd->net_dev->name);
1276
 
                        TRACEEXIT2(return STATUS_SUCCESS);
 
1336
                        irp->io_status.status = status = STATUS_SUCCESS;
 
1337
                        IoCompleteRequest(irp, IO_NO_INCREMENT);
 
1338
                        break;
1277
1339
                } else {
1278
 
                        if (test_bit(HW_SUSPENDED, &wnd->hw_status) ||
1279
 
                            test_bit(HW_HALTED, &wnd->hw_status))
1280
 
                                return STATUS_FAILURE;
1281
 
                        DBGTRACE2("irql: %d", current_irql());
1282
 
                        netif_poll_disable(wnd->net_dev);
1283
 
                        if (netif_running(wnd->net_dev)) {
1284
 
                                netif_tx_disable(wnd->net_dev);
1285
 
                                netif_device_detach(wnd->net_dev);
1286
 
                        }
1287
 
                        hangcheck_del(wnd);
1288
 
                        stats_timer_del(wnd);
1289
1340
                        ndis_status = miniport_set_power_state(wnd, state);
1290
 
                        /* TODO: we need to send the IRP back with
1291
 
                         * error so that pdo can restart device */
 
1341
                        /* TODO: handle error case */
1292
1342
                        if (ndis_status != NDIS_STATUS_SUCCESS)
1293
1343
                                WARNING("setting power to %d failed: %08X",
1294
1344
                                        state, ndis_status);
1295
 
                        return IopPassIrpDown(wnd->nmb->pdo, irp);
 
1345
                        status = LIN2WIN2(IoAsyncForwardIrp, wnd->nmb->pdo, irp);
1296
1346
                }
1297
 
                status = STATUS_SUCCESS;
1298
1347
                break;
1299
1348
        case IRP_MN_QUERY_POWER:
1300
 
                ndis_status = miniport_query_int(wnd, OID_PNP_QUERY_POWER,
1301
 
                                                 &state);
1302
 
                DBGTRACE2("query_power to state %d returns %08X",
1303
 
                          state, ndis_status);
1304
 
                if (ndis_status == NDIS_STATUS_SUCCESS)
1305
 
                        status = STATUS_SUCCESS;
1306
 
                else
1307
 
                        status = STATUS_FAILURE;
 
1349
                if (wnd->pm_capa) {
 
1350
                        ndis_status = miniport_query_info(wnd,
 
1351
                                                          OID_PNP_QUERY_POWER,
 
1352
                                                          &state, sizeof(state));
 
1353
                        DBGTRACE2("%d, %08X", state, ndis_status);
 
1354
                        /* this OID must always succeed */
 
1355
                        if (ndis_status != NDIS_STATUS_SUCCESS)
 
1356
                                DBGTRACE1("query power returns %08X",
 
1357
                                          ndis_status);
 
1358
                        irp->io_status.status = STATUS_SUCCESS;
 
1359
                } else
 
1360
                        irp->io_status.status = STATUS_SUCCESS;
 
1361
                status = LIN2WIN2(IoPassIrpDown, wnd->nmb->pdo, irp);
1308
1362
                break;
1309
1363
        case IRP_MN_WAIT_WAKE:
1310
1364
        case IRP_MN_POWER_SEQUENCE:
1311
1365
                /* TODO: implement WAIT_WAKE */
1312
 
                status = STATUS_NOT_SUPPORTED;
 
1366
                status = LIN2WIN2(IoPassIrpDown, wnd->nmb->pdo, irp);
1313
1367
                break;
1314
1368
        default:
1315
 
                return IopPassIrpDown(wnd->nmb->pdo, irp);
 
1369
                status = LIN2WIN2(IoPassIrpDown, wnd->nmb->pdo, irp);
 
1370
                break;
1316
1371
        }
1317
 
        irp->io_status.status_info = 0;
1318
 
        irp->io_status.status = status;
1319
 
        IoCompleteRequest(irp, IO_NO_INCREMENT);
1320
 
        return status;
 
1372
        IOEXIT(return status);
1321
1373
}
1322
1374
 
1323
 
STDCALL NTSTATUS NdisDispatchPnp(struct device_object *fdo,
1324
 
                                 struct irp *irp)
 
1375
/* called as Windows function, so call WIN2LIN2 before accessing
 
1376
 * arguments */
 
1377
wstdcall NTSTATUS NdisDispatchPnp(struct device_object *fdo, struct irp *irp)
1325
1378
{
1326
1379
        struct io_stack_location *irp_sl;
1327
1380
        struct wrap_ndis_device *wnd;
1328
1381
        struct device_object *pdo;
1329
1382
        NTSTATUS status;
1330
1383
 
1331
 
        IOENTER("fdo: %p, irp: %p", fdo, irp);
 
1384
        WIN2LIN2(fdo, irp);
 
1385
 
 
1386
        IOTRACE("fdo: %p, irp: %p", fdo, irp);
1332
1387
        irp_sl = IoGetCurrentIrpStackLocation(irp);
1333
1388
        wnd = fdo->reserved;
1334
1389
        pdo = wnd->nmb->pdo;
1335
 
        IOTRACE("fn %d:%d, wnd: %p, fdo: %p, pdo: %p",
1336
 
                irp_sl->major_fn, irp_sl->minor_fn, wnd, fdo, pdo);
1337
1390
        switch (irp_sl->minor_fn) {
1338
1391
        case IRP_MN_START_DEVICE:
1339
 
                IoCopyCurrentIrpStackLocationToNext(irp);
1340
 
                IoSetCompletionRoutine(irp, IrpStopCompletion, wnd, TRUE,
1341
 
                                       FALSE, FALSE);
1342
 
                status = IoCallDriver(pdo, irp);
 
1392
                status = LIN2WIN2(IoSyncForwardIrp, pdo, irp);
1343
1393
                if (status != STATUS_SUCCESS)
1344
1394
                        break;
1345
1395
                if (ndis_start_device(wnd) == NDIS_STATUS_SUCCESS)
1346
1396
                        status = STATUS_SUCCESS;
1347
1397
                else
1348
1398
                        status = STATUS_FAILURE;
 
1399
                irp->io_status.status = status;
 
1400
                IoCompleteRequest(irp, IO_NO_INCREMENT);
1349
1401
                break;
1350
1402
        case IRP_MN_QUERY_STOP_DEVICE:
1351
 
                return IopPassIrpDown(pdo, irp);
 
1403
                /* TODO: implement in NDIS */
 
1404
                status = LIN2WIN2(IoPassIrpDown, wnd->nmb->pdo, irp);
 
1405
                break;
1352
1406
        case IRP_MN_STOP_DEVICE:
1353
1407
                miniport_halt(wnd);
1354
 
                return IopPassIrpDown(pdo, irp);
 
1408
                irp->io_status.status = STATUS_SUCCESS;
 
1409
                status = LIN2WIN2(IoAsyncForwardIrp, pdo, irp);
 
1410
                break;
1355
1411
        case IRP_MN_REMOVE_DEVICE:
1356
1412
                DBGTRACE1("%s", wnd->net_dev->name);
1357
 
                if (ndis_remove_device(wnd) != NDIS_STATUS_SUCCESS) {
 
1413
                if (wnd->wd->surprise_removed == TRUE)
 
1414
                        miniport_pnp_event(wnd,
 
1415
                                           NdisDevicePnPEventSurpriseRemoved);
 
1416
                if (ndis_remove_device(wnd)) {
1358
1417
                        status = STATUS_FAILURE;
1359
1418
                        break;
1360
1419
                }
1361
 
                return IopPassIrpDown(pdo, irp);
 
1420
                /* wnd is already freed */
 
1421
                status = LIN2WIN2(IoAsyncForwardIrp, pdo, irp);
 
1422
                IoDetachDevice(fdo);
 
1423
                IoDeleteDevice(fdo);
 
1424
                break;
1362
1425
        default:
1363
 
                return IopPassIrpDown(pdo, irp);
1364
 
        }
1365
 
        irp->io_status.status = status;
1366
 
        IOTRACE("res: %08X", status);
1367
 
        IoCompleteRequest(irp, IO_NO_INCREMENT);
1368
 
        return status;
 
1426
                status = LIN2WIN2(IoAsyncForwardIrp, pdo, irp);
 
1427
                break;
 
1428
        }
 
1429
        IOTRACE("status: %08X", status);
 
1430
        IOEXIT(return status);
 
1431
}
 
1432
 
 
1433
static int set_task_offload(struct wrap_ndis_device *wnd, void *buf,
 
1434
                            const int buf_size)
 
1435
{
 
1436
#if 0
 
1437
        struct ndis_task_offload_header *task_offload_header;
 
1438
        struct ndis_task_offload *task_offload;
 
1439
        struct ndis_task_tcp_ip_checksum *task_tcp_ip_csum = NULL;
 
1440
        struct ndis_task_tcp_ip_checksum csum;
 
1441
        NDIS_STATUS status;
 
1442
 
 
1443
        memset(buf, 0, buf_size);
 
1444
        task_offload_header = buf;
 
1445
        task_offload_header->version = NDIS_TASK_OFFLOAD_VERSION;
 
1446
        task_offload_header->size = sizeof(*task_offload_header);
 
1447
        task_offload_header->encapsulation_format.encapsulation =
 
1448
                IEEE_802_3_Encapsulation;
 
1449
        status = miniport_query_info(wnd, OID_TCP_TASK_OFFLOAD, buf, buf_size);
 
1450
        DBGTRACE1("%08X", status);
 
1451
        if (status != NDIS_STATUS_SUCCESS)
 
1452
                TRACEEXIT1(return -1);
 
1453
        if (task_offload_header->offset_first_task == 0)
 
1454
                TRACEEXIT1(return -1);
 
1455
        task_offload = ((void *)task_offload_header +
 
1456
                        task_offload_header->offset_first_task);
 
1457
        while (1) {
 
1458
                DBGTRACE1("%d, %d", task_offload->version, task_offload->task);
 
1459
                switch(task_offload->task) {
 
1460
                case TcpIpChecksumNdisTask:
 
1461
                        task_tcp_ip_csum = (void *)task_offload->task_buf;
 
1462
                        break;
 
1463
                default:
 
1464
                        DBGTRACE1("%d", task_offload->task);
 
1465
                        break;
 
1466
                }
 
1467
                if (task_offload->offset_next_task == 0)
 
1468
                        break;
 
1469
                task_offload = (void *)task_offload +
 
1470
                        task_offload->offset_next_task;
 
1471
        }
 
1472
        if (!task_tcp_ip_csum)
 
1473
                TRACEEXIT1(return -1);
 
1474
        memcpy(&csum, task_tcp_ip_csum, sizeof(csum));
 
1475
 
 
1476
        task_offload_header->encapsulation_format.flags.fixed_header_size = 1;
 
1477
        task_offload_header->encapsulation_format.header_size =
 
1478
                sizeof(struct ethhdr);
 
1479
        task_offload_header->offset_first_task = sizeof(*task_offload_header);
 
1480
        task_offload = ((void *)task_offload_header +
 
1481
                        task_offload_header->offset_first_task);
 
1482
        memcpy(task_offload->task_buf, &csum, sizeof(csum));
 
1483
        task_offload->offset_next_task = 0;
 
1484
        task_offload->size = sizeof(*task_offload);
 
1485
        task_offload->task = TcpIpChecksumNdisTask;
 
1486
        task_offload->task_buf_length = sizeof(csum);
 
1487
        status = miniport_set_info(wnd, OID_TCP_TASK_OFFLOAD,
 
1488
                                   task_offload_header,
 
1489
                                   sizeof(*task_offload_header) +
 
1490
                                   sizeof(*task_offload) + sizeof(csum));
 
1491
        DBGTRACE1("%08X", status);
 
1492
        if (status != NDIS_STATUS_SUCCESS)
 
1493
                TRACEEXIT2(return -1);
 
1494
        DBGTRACE1("%08x, %08x", csum.v4_tx.value, csum.v4_rx.value);
 
1495
        if (csum.v4_tx.ip_csum) {
 
1496
                wnd->tx_csum_info.tx.v4 = 1;
 
1497
                if (csum.v4_tx.tcp_csum && csum.v4_tx.udp_csum) {
 
1498
                        wnd->net_dev->features |= NETIF_F_HW_CSUM;
 
1499
                        wnd->tx_csum_info.tx.tcp = 1;
 
1500
                        wnd->tx_csum_info.tx.ip = 1;
 
1501
                        wnd->tx_csum_info.tx.udp = 1;
 
1502
                        DBGTRACE1("hw_csum");
 
1503
                } else {
 
1504
                        wnd->net_dev->features |= NETIF_F_IP_CSUM;
 
1505
                        wnd->tx_csum_info.tx.ip = 1;
 
1506
                        DBGTRACE1("ip_csum");
 
1507
                }
 
1508
        }
 
1509
        wnd->rx_csum = csum.v4_rx;
 
1510
#endif
 
1511
        TRACEEXIT1(return 0);
 
1512
}
 
1513
 
 
1514
static void get_supported_oids(struct wrap_ndis_device *wnd)
 
1515
{
 
1516
        NDIS_STATUS res;
 
1517
        int i, n, needed;
 
1518
        ndis_oid *oids;
 
1519
 
 
1520
        res = miniport_query_info_needed(wnd, OID_GEN_SUPPORTED_LIST, NULL, 0,
 
1521
                                         &needed);
 
1522
        if (!(res == NDIS_STATUS_BUFFER_TOO_SHORT ||
 
1523
              res == NDIS_STATUS_INVALID_LENGTH))
 
1524
                TRACEEXIT1(return);
 
1525
        oids = kmalloc(needed, GFP_KERNEL);
 
1526
        if (!oids) {
 
1527
                DBGTRACE1("couldn't allocate memory");
 
1528
                TRACEEXIT1(return);
 
1529
        }
 
1530
        res = miniport_query_info(wnd, OID_GEN_SUPPORTED_LIST, oids, needed);
 
1531
        if (res) {
 
1532
                DBGTRACE1("failed: %08X", res);
 
1533
                kfree(oids);
 
1534
                TRACEEXIT1(return);
 
1535
        }
 
1536
        for (i = 0, n = needed / sizeof(*oids); i < n; i++) {
 
1537
                DBGTRACE1("oid: %08X", oids[i]);
 
1538
                /* if a wireless device didn't say so for
 
1539
                 * OID_GEN_PHYSICAL_MEDIUM (they should, but in case) */
 
1540
                if (wnd->physical_medium != NdisPhysicalMediumWirelessLan &&
 
1541
                    oids[i] == OID_802_11_SSID)
 
1542
                        wnd->physical_medium = NdisPhysicalMediumWirelessLan;
 
1543
        }
 
1544
        kfree(oids);
 
1545
        TRACEEXIT1(return);
1369
1546
}
1370
1547
 
1371
1548
static NDIS_STATUS ndis_start_device(struct wrap_ndis_device *wnd)
1373
1550
        struct wrap_device *wd;
1374
1551
        struct net_device *net_dev;
1375
1552
        NDIS_STATUS ndis_status;
 
1553
        char *buf;
 
1554
        const int buf_size = 256;
1376
1555
        mac_address mac;
1377
 
        char buf[256];
1378
1556
 
1379
 
        if (miniport_init(wnd) != NDIS_STATUS_SUCCESS)
1380
 
                return NDIS_STATUS_FAILURE;
1381
 
        /* NB: xmit_array is used to recognize if device is being
 
1557
        ndis_status = miniport_init(wnd);
 
1558
        if (ndis_status == NDIS_STATUS_NOT_RECOGNIZED)
 
1559
                TRACEEXIT1(return NDIS_STATUS_SUCCESS);
 
1560
        if (ndis_status != NDIS_STATUS_SUCCESS)
 
1561
                TRACEEXIT1(return ndis_status);
 
1562
        /* NB: tx_array is used to recognize if device is being
1382
1563
         * started for the first time or being re-started */
1383
 
        if (wnd->xmit_array)
 
1564
        if (wnd->tx_array)
1384
1565
                TRACEEXIT2(return NDIS_STATUS_SUCCESS);
1385
1566
        wd = wnd->wd;
1386
1567
        net_dev = wnd->net_dev;
1387
 
        show_supported_oids(wnd);
1388
 
        strncpy(net_dev->name, if_name, IFNAMSIZ-1);
1389
 
        net_dev->name[IFNAMSIZ-1] = '\0';
1390
 
 
1391
 
        DBGTRACE1("%s: querying for mac", DRIVER_NAME);
 
1568
 
 
1569
        ndis_status = miniport_query_int(wnd, OID_GEN_PHYSICAL_MEDIUM,
 
1570
                                         &wnd->physical_medium);
 
1571
        if (ndis_status != NDIS_STATUS_SUCCESS)
 
1572
                wnd->physical_medium = NdisPhysicalMediumUnspecified;
 
1573
 
 
1574
        get_supported_oids(wnd);
 
1575
        strncpy(net_dev->name, if_name, IFNAMSIZ - 1);
 
1576
        net_dev->name[IFNAMSIZ - 1] = '\0';
 
1577
 
1392
1578
        ndis_status = miniport_query_info(wnd, OID_802_3_CURRENT_ADDRESS,
1393
1579
                                          mac, sizeof(mac));
1394
1580
        if (ndis_status) {
1395
1581
                ERROR("couldn't get mac address: %08X", ndis_status);
1396
 
                goto err_start;
 
1582
                return ndis_status;
1397
1583
        }
1398
1584
        DBGTRACE1("mac:" MACSTR, MAC2STR(mac));
1399
1585
        memcpy(&net_dev->dev_addr, mac, ETH_ALEN);
1400
1586
 
1401
1587
        net_dev->open = ndis_open;
1402
 
        net_dev->hard_start_xmit = start_xmit;
 
1588
        net_dev->hard_start_xmit = tx_skbuff;
1403
1589
        net_dev->stop = ndis_close;
1404
1590
        net_dev->get_stats = ndis_get_stats;
1405
 
        net_dev->do_ioctl = ndis_ioctl;
 
1591
        net_dev->do_ioctl = NULL;
 
1592
        if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) {
1406
1593
#if WIRELESS_EXT < 19
1407
 
        net_dev->get_wireless_stats = get_wireless_stats;
 
1594
                net_dev->get_wireless_stats = get_wireless_stats;
1408
1595
#endif
1409
 
        net_dev->wireless_handlers =
1410
 
                (struct iw_handler_def *)&ndis_handler_def;
 
1596
                net_dev->wireless_handlers = &ndis_handler_def;
 
1597
        } else
 
1598
                wnd->tx_ok = 1;
1411
1599
        net_dev->set_multicast_list = ndis_set_multicast_list;
1412
1600
        net_dev->set_mac_address = ndis_set_mac_addr;
1413
 
#ifdef HAVE_ETHTOOL
 
1601
#if defined(HAVE_ETHTOOL)
1414
1602
        net_dev->ethtool_ops = &ndis_ethtool_ops;
1415
1603
#endif
1416
1604
        if (wnd->ndis_irq)
1417
1605
                net_dev->irq = wnd->ndis_irq->irq.irq;
1418
1606
        net_dev->mem_start = wnd->mem_start;
1419
1607
        net_dev->mem_end = wnd->mem_end;
 
1608
        ndis_status = miniport_query_int(wnd, OID_802_3_MAXIMUM_LIST_SIZE,
 
1609
                                         &wnd->multicast_size);
 
1610
        if (ndis_status != NDIS_STATUS_SUCCESS || wnd->multicast_size < 0)
 
1611
                wnd->multicast_size = 0;
 
1612
        if (wnd->multicast_size > 0)
 
1613
                net_dev->flags |= IFF_MULTICAST;
 
1614
        else
 
1615
                net_dev->flags &= ~IFF_MULTICAST;
 
1616
#ifdef CONFIG_NET_POLL_CONTROLLER
 
1617
        net_dev->poll_controller = ndis_poll_controller;
 
1618
#endif
 
1619
 
 
1620
        buf = kmalloc(buf_size, GFP_KERNEL);
 
1621
        if (!buf) {
 
1622
                WARNING("couldn't allocate memory");
 
1623
                goto err_start;
 
1624
        }
 
1625
 
 
1626
        set_task_offload(wnd, buf, buf_size);
1420
1627
        if (register_netdev(net_dev)) {
1421
1628
                ERROR("cannot register net device %s", net_dev->name);
1422
 
                goto err_start;
 
1629
                goto err_register;
1423
1630
        }
1424
1631
 
1425
 
        memset(buf, 0, sizeof(buf));
 
1632
        memset(buf, 0, buf_size);
1426
1633
        ndis_status = miniport_query_info(wnd, OID_GEN_VENDOR_DESCRIPTION,
1427
 
                                          buf, sizeof(buf));
 
1634
                                          buf, buf_size);
1428
1635
        if (ndis_status == NDIS_STATUS_SUCCESS)
1429
1636
                printk(KERN_INFO "%s: vendor: '%s'\n", net_dev->name, buf);
1430
1637
 
1431
 
        printk(KERN_INFO "%s: %s ethernet device " MACSTR " using driver %s,"
 
1638
        printk(KERN_INFO "%s: %s ethernet device " MACSTR " using %sdriver %s,"
1432
1639
               " %s\n", net_dev->name, DRIVER_NAME, MAC2STR(net_dev->dev_addr),
 
1640
               wnd->attributes & NDIS_ATTRIBUTE_DESERIALIZE ? "" : "serialized ",
1433
1641
               wnd->wd->driver->name, wnd->wd->conf_file_name);
1434
1642
 
1435
 
        check_capa(wnd);
1436
 
        DBGTRACE1("capbilities = %ld", wnd->capa.encr);
1437
 
        printk(KERN_INFO "%s: encryption modes supported: %s%s%s%s%s%s%s\n",
1438
 
               net_dev->name,
1439
 
               test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr) ?
1440
 
               "WEP" : "none",
1441
 
 
1442
 
               test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr) ?
1443
 
               "; TKIP with WPA" : "",
1444
 
               test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ?
1445
 
               ", WPA2" : "",
1446
 
               test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ?
1447
 
               ", WPA2PSK" : "",
1448
 
 
1449
 
               test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr) ?
1450
 
               "; AES/CCMP with WPA" : "",
1451
 
               test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ?
1452
 
               ", WPA2" : "",
1453
 
               test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ?
1454
 
               ", WPA2PSK" : "");
1455
 
 
1456
 
        if (test_bit(ATTR_SERIALIZED, &wnd->attributes)) {
 
1643
        if (wnd->attributes & NDIS_ATTRIBUTE_DESERIALIZE) {
 
1644
                /* deserialized drivers don't have a limit, but we
 
1645
                 * keep max at TX_RING_SIZE to allocate tx_array
 
1646
                 * below */
 
1647
                wnd->max_tx_packets = TX_RING_SIZE;
 
1648
        } else {
1457
1649
                ndis_status =
1458
1650
                        miniport_query_int(wnd, OID_GEN_MAXIMUM_SEND_PACKETS,
1459
 
                                           &wnd->max_send_packets);
 
1651
                                           &wnd->max_tx_packets);
1460
1652
                if (ndis_status == NDIS_STATUS_NOT_SUPPORTED)
1461
 
                        wnd->max_send_packets = 1;
1462
 
                if (wnd->max_send_packets > XMIT_RING_SIZE)
1463
 
                        wnd->max_send_packets = XMIT_RING_SIZE;
1464
 
        } else {
1465
 
                /* deserialized drivers don't have a limit, but we
1466
 
                 * keep max at XMIT_RING_SIZE to allocate xmit_array
1467
 
                 * below */
1468
 
                wnd->max_send_packets = XMIT_RING_SIZE;
 
1653
                        wnd->max_tx_packets = 1;
 
1654
                if (wnd->max_tx_packets > TX_RING_SIZE)
 
1655
                        wnd->max_tx_packets = TX_RING_SIZE;
1469
1656
        }
1470
 
 
1471
 
        DBGTRACE1("maximum send packets: %d", wnd->max_send_packets);
1472
 
        wnd->xmit_array =
1473
 
                kmalloc(sizeof(struct ndis_packet *) * wnd->max_send_packets,
 
1657
        DBGTRACE1("maximum send packets: %d", wnd->max_tx_packets);
 
1658
        wnd->tx_array =
 
1659
                kmalloc(sizeof(struct ndis_packet *) * wnd->max_tx_packets,
1474
1660
                        GFP_KERNEL);
1475
 
        if (!wnd->xmit_array) {
 
1661
        if (!wnd->tx_array) {
1476
1662
                ERROR("couldn't allocate memory for tx_packets");
1477
1663
                goto err_start;
1478
1664
 
1479
1665
        }
1480
1666
        /* we need at least one extra packet for
1481
1667
         * EthRxIndicateHandler */
1482
 
        NdisAllocatePacketPoolEx(&ndis_status, &wnd->wrapper_packet_pool,
1483
 
                                 wnd->max_send_packets + 1, 0,
 
1668
        NdisAllocatePacketPoolEx(&ndis_status, &wnd->tx_packet_pool,
 
1669
                                 wnd->max_tx_packets + 1, 0,
1484
1670
                                 PROTOCOL_RESERVED_SIZE_IN_PACKET);
1485
1671
        if (ndis_status != NDIS_STATUS_SUCCESS) {
1486
1672
                ERROR("couldn't allocate packet pool");
1487
1673
                goto packet_pool_err;
1488
1674
        }
1489
 
        NdisAllocateBufferPool(&ndis_status, &wnd->wrapper_buffer_pool,
1490
 
                               wnd->max_send_packets + 4);
 
1675
        NdisAllocateBufferPool(&ndis_status, &wnd->tx_buffer_pool,
 
1676
                               wnd->max_tx_packets + 4);
1491
1677
        if (ndis_status != NDIS_STATUS_SUCCESS) {
1492
1678
                ERROR("couldn't allocate buffer pool");
1493
1679
                goto buffer_pool_err;
1494
1680
        }
1495
 
        DBGTRACE1("pool: %p", wnd->wrapper_buffer_pool);
1496
 
        miniport_set_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE,
1497
 
                         Ndis802_11Automode);
1498
 
//      miniport_set_int(wnd, OID_802_11_POWER_MODE, NDIS_POWER_OFF);
1499
 
        /* check_capa changes auth_mode and encr_mode, so set them again */
1500
 
        set_infra_mode(wnd, Ndis802_11Infrastructure);
1501
 
        set_auth_mode(wnd, Ndis802_11AuthModeOpen);
1502
 
        set_encr_mode(wnd, Ndis802_11EncryptionDisabled);
1503
 
        set_scan(wnd);
1504
 
        set_privacy_filter(wnd, Ndis802_11PrivFilterAcceptAll);
1505
 
        set_essid(wnd, "", 0);
1506
 
 
 
1681
        DBGTRACE1("pool: %p", wnd->tx_buffer_pool);
 
1682
        if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) {
 
1683
                miniport_set_int(wnd, OID_802_11_POWER_MODE, NDIS_POWER_OFF);
 
1684
                miniport_set_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE,
 
1685
                                 Ndis802_11Automode);
 
1686
                get_encryption_capa(wnd);
 
1687
                DBGTRACE1("capbilities = %ld", wnd->capa.encr);
 
1688
                printk(KERN_INFO "%s: encryption modes supported: "
 
1689
                       "%s%s%s%s%s%s%s\n", net_dev->name,
 
1690
                       test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr) ?
 
1691
                       "WEP" : "none",
 
1692
 
 
1693
                       test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr) ?
 
1694
                       "; TKIP with WPA" : "",
 
1695
                       test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ?
 
1696
                       ", WPA2" : "",
 
1697
                       test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ?
 
1698
                       ", WPA2PSK" : "",
 
1699
 
 
1700
                       test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr) ?
 
1701
                       "; AES/CCMP with WPA" : "",
 
1702
                       test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ?
 
1703
                       ", WPA2" : "",
 
1704
                       test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ?
 
1705
                       ", WPA2PSK" : "");
 
1706
 
 
1707
                set_infra_mode(wnd, Ndis802_11Infrastructure);
 
1708
                set_scan(wnd);
 
1709
                set_priv_filter(wnd, Ndis802_11PrivFilterAcceptAll);
 
1710
                set_auth_mode(wnd, Ndis802_11AuthModeOpen);
 
1711
                set_encr_mode(wnd, Ndis802_11EncryptionDisabled);
 
1712
                set_essid(wnd, "", 0);
 
1713
        }
 
1714
        kfree(buf);
1507
1715
        wrap_procfs_add_ndis_device(wnd);
 
1716
        add_stats_timer(wnd);
1508
1717
        TRACEEXIT1(return NDIS_STATUS_SUCCESS);
1509
1718
 
1510
1719
buffer_pool_err:
1511
 
        wnd->wrapper_buffer_pool = NULL;
1512
 
        if (wnd->wrapper_packet_pool) {
1513
 
                NdisFreePacketPool(wnd->wrapper_packet_pool);
1514
 
                wnd->wrapper_packet_pool = NULL;
 
1720
        wnd->tx_buffer_pool = NULL;
 
1721
        if (wnd->tx_packet_pool) {
 
1722
                NdisFreePacketPool(wnd->tx_packet_pool);
 
1723
                wnd->tx_packet_pool = NULL;
1515
1724
        }
1516
1725
packet_pool_err:
1517
 
        kfree(wnd->xmit_array);
1518
 
        wnd->xmit_array = NULL;
 
1726
        kfree(wnd->tx_array);
 
1727
        wnd->tx_array = NULL;
 
1728
err_register:
 
1729
        kfree(buf);
1519
1730
err_start:
1520
1731
        ndis_remove_device(wnd);
1521
1732
        TRACEEXIT1(return NDIS_STATUS_FAILURE);
1522
1733
}
1523
1734
 
1524
 
static NDIS_STATUS ndis_remove_device(struct wrap_ndis_device *wnd)
 
1735
static int ndis_remove_device(struct wrap_ndis_device *wnd)
1525
1736
{
1526
 
        KIRQL irql;
 
1737
        int tx_pending;
1527
1738
 
1528
 
        set_bit(SHUTDOWN, &wnd->wrap_ndis_work);
1529
 
        miniport_pnp_event(wnd, NdisDevicePnPEventSurpriseRemoved);
 
1739
        set_bit(SHUTDOWN, &wnd->wrap_ndis_pending_work);
 
1740
        wnd->tx_ok = 0;
1530
1741
        ndis_close(wnd->net_dev);
1531
1742
        netif_carrier_off(wnd->net_dev);
1532
 
        wrap_procfs_remove_ndis_device(wnd);
 
1743
        cancel_delayed_work(&wnd->wrap_ndis_work);
 
1744
        /* In 2.4 kernels, this function is called in atomic context,
 
1745
         * so we can't (don't need to?) wait on mutex. */
 
1746
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 
1747
        /* if device is suspended, but resume failed, tx_ring_mutex is
 
1748
         * already locked */
 
1749
        down_trylock(&wnd->tx_ring_mutex);
 
1750
#endif
 
1751
        tx_pending = wnd->tx_ring_end - wnd->tx_ring_start;
 
1752
        if (tx_pending < 0)
 
1753
                tx_pending += TX_RING_SIZE;
 
1754
        else if (tx_pending == 0 && wnd->is_tx_ring_full)
 
1755
                tx_pending = TX_RING_SIZE - 1;
 
1756
        wnd->is_tx_ring_full = 0;
1533
1757
        /* throw away pending packets */
1534
 
        irql = kspin_lock_irql(&wnd->xmit_lock, DISPATCH_LEVEL);
1535
 
        while (wnd->xmit_ring_pending) {
 
1758
        while (tx_pending > 0) {
1536
1759
                struct ndis_packet *packet;
1537
1760
 
1538
 
                packet = wnd->xmit_ring[wnd->xmit_ring_start];
1539
 
                free_send_packet(wnd, packet);
1540
 
                wnd->xmit_ring_start =
1541
 
                        (wnd->xmit_ring_start + 1) % XMIT_RING_SIZE;
1542
 
                wnd->xmit_ring_pending--;
 
1761
                packet = wnd->tx_ring[wnd->tx_ring_start];
 
1762
                free_tx_packet(wnd, packet, NDIS_STATUS_CLOSING);
 
1763
                wnd->tx_ring_start = (wnd->tx_ring_start + 1) % TX_RING_SIZE;
 
1764
                tx_pending--;
1543
1765
        }
1544
 
        kspin_unlock_irql(&wnd->xmit_lock, irql);
 
1766
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 
1767
        up(&wnd->tx_ring_mutex);
 
1768
#endif
 
1769
        wrap_procfs_remove_ndis_device(wnd);
1545
1770
        miniport_halt(wnd);
1546
1771
        ndis_exit_device(wnd);
1547
 
        /* flush_scheduled_work here causes crash with 2.4 kernels */
1548
 
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
1549
 
        flush_scheduled_work();
1550
 
#endif
1551
 
        if (wnd->wrapper_packet_pool) {
1552
 
                NdisFreePacketPool(wnd->wrapper_packet_pool);
1553
 
                wnd->wrapper_packet_pool = NULL;
1554
 
        }
1555
 
        if (wnd->wrapper_buffer_pool) {
1556
 
                NdisFreeBufferPool(wnd->wrapper_buffer_pool);
1557
 
                wnd->wrapper_buffer_pool = NULL;
1558
 
        }
1559
 
        IoDetachDevice(wnd->nmb->next_device);
1560
 
        IoDeleteDevice(wnd->nmb->fdo);
1561
 
        if (wnd->xmit_array)
1562
 
                kfree(wnd->xmit_array);
 
1772
 
 
1773
        if (wnd->tx_packet_pool) {
 
1774
                NdisFreePacketPool(wnd->tx_packet_pool);
 
1775
                wnd->tx_packet_pool = NULL;
 
1776
        }
 
1777
        if (wnd->tx_buffer_pool) {
 
1778
                NdisFreeBufferPool(wnd->tx_buffer_pool);
 
1779
                wnd->tx_buffer_pool = NULL;
 
1780
        }
 
1781
        if (wnd->tx_array)
 
1782
                kfree(wnd->tx_array);
1563
1783
        printk(KERN_INFO "%s: device %s removed\n", DRIVER_NAME,
1564
1784
               wnd->net_dev->name);
1565
1785
        unregister_netdev(wnd->net_dev);
1566
1786
        free_netdev(wnd->net_dev);
1567
 
        TRACEEXIT2(return NDIS_STATUS_SUCCESS);
 
1787
        TRACEEXIT2(return 0);
1568
1788
}
1569
1789
 
1570
 
static STDCALL NTSTATUS NdisAddDevice(struct driver_object *drv_obj,
 
1790
static wstdcall NTSTATUS NdisAddDevice(struct driver_object *drv_obj,
1571
1791
                                      struct device_object *pdo)
1572
1792
{
1573
1793
        struct device_object *fdo;
1576
1796
        struct wrap_ndis_device *wnd;
1577
1797
        struct net_device *net_dev;
1578
1798
        struct wrap_device *wd;
1579
 
        int i;
 
1799
        unsigned long i;
1580
1800
 
1581
1801
        TRACEENTER2("%p, %p", drv_obj, pdo);
1582
1802
        if (strlen(if_name) > (IFNAMSIZ-1)) {
1607
1827
 
1608
1828
        nmb = ((void *)wnd) + sizeof(*wnd);
1609
1829
        wnd->nmb = nmb;
 
1830
#if defined(DEBUG) && DEBUG >= 6
 
1831
        /* poison nmb so if a driver accesses uninitialized pointers, we
 
1832
         * know what it is */
 
1833
        for (i = 0; i < sizeof(*nmb) / sizeof(unsigned long); i++)
 
1834
                ((unsigned long *)nmb)[i] = i + 0x8a3fc1;
 
1835
#endif
 
1836
 
1610
1837
        nmb->wnd = wnd;
1611
 
        wnd->nmb->pdo = pdo;
 
1838
        nmb->pdo = pdo;
1612
1839
        wd->wnd = wnd;
1613
1840
        wnd->wd = wd;
1614
1841
        nmb->filterdbs.eth_db = nmb;
1620
1847
        init_nmb_functions(nmb);
1621
1848
        wnd->net_dev = net_dev;
1622
1849
        wnd->ndis_irq = NULL;
1623
 
        kspin_lock_init(&wnd->xmit_lock);
1624
 
        init_MUTEX(&wnd->ndis_comm_mutex);
 
1850
        init_MUTEX_LOCKED(&wnd->tx_ring_mutex);
 
1851
        init_MUTEX_LOCKED(&wnd->ndis_comm_mutex);
1625
1852
        init_waitqueue_head(&wnd->ndis_comm_wq);
1626
1853
        wnd->ndis_comm_done = 0;
1627
 
        /* don't send packets until the card is associated */
1628
 
        wnd->send_ok = 0;
1629
 
        INIT_WORK(&wnd->xmit_work, xmit_worker, wnd);
1630
 
        wnd->xmit_ring_start = 0;
1631
 
        wnd->xmit_ring_pending = 0;
1632
 
        kspin_lock_init(&wnd->send_packet_done_lock);
 
1854
        wnd->tx_ok = 0;
 
1855
        INIT_WORK(&wnd->tx_work, tx_worker, wnd);
 
1856
        wnd->tx_ring_start = 0;
 
1857
        wnd->tx_ring_end = 0;
 
1858
        wnd->is_tx_ring_full = 0;
 
1859
        nt_spin_lock_init(&wnd->tx_stats_lock);
1633
1860
        wnd->encr_mode = Ndis802_11EncryptionDisabled;
1634
1861
        wnd->auth_mode = Ndis802_11AuthModeOpen;
1635
1862
        wnd->capa.encr = 0;
1636
1863
        wnd->capa.auth = 0;
1637
1864
        wnd->attributes = 0;
1638
 
        wnd->map_count = 0;
1639
 
        wnd->map_dma_addr = NULL;
 
1865
        wnd->dma_map_count = 0;
 
1866
        wnd->dma_map_addr = NULL;
1640
1867
        wnd->nick[0] = 0;
1641
 
        wnd->hangcheck_interval = hangcheck_interval;
1642
1868
        init_timer(&wnd->hangcheck_timer);
1643
1869
        wnd->scan_timestamp = 0;
1644
1870
        init_timer(&wnd->stats_timer);
1645
 
        wnd->wrap_ndis_work = 0;
 
1871
        wnd->wrap_ndis_pending_work = 0;
1646
1872
        memset(&wnd->essid, 0, sizeof(wnd->essid));
1647
1873
        memset(&wnd->encr_info, 0, sizeof(wnd->encr_info));
1648
1874
        wnd->infrastructure_mode = Ndis802_11Infrastructure;
1649
 
        INIT_WORK(&wnd->wrap_ndis_worker, wrap_ndis_worker_proc, wnd);
 
1875
        INIT_WORK(&wnd->wrap_ndis_work, wrap_ndis_worker, wnd);
1650
1876
        wnd->hw_status = 0;
1651
 
        set_bit(HW_AVAILABLE, &wnd->hw_status);
1652
1877
        if (wd->driver->ndis_driver)
1653
1878
                wd->driver->ndis_driver->miniport.shutdown = NULL;
1654
 
        /* ZyDas driver doesn't call completion function when
1655
 
         * querying for stats or rssi, so disable stats */
1656
 
        if (stricmp(wd->driver->name, "zd1211u") == 0)
1657
 
                wnd->stats_enabled = FALSE;
1658
 
        else
1659
 
                wnd->stats_enabled = TRUE;
 
1879
        wnd->stats_enabled = TRUE;
 
1880
        wnd->rx_csum.value = 0;
1660
1881
 
1661
1882
        fdo->reserved = wnd;
1662
 
        nmb = wnd->nmb;
1663
1883
        nmb->fdo = fdo;
1664
1884
        nmb->next_device = IoAttachDeviceToDeviceStack(fdo, pdo);
1665
1885
        DBGTRACE1("nmb: %p, pdo: %p, fdo: %p, attached: %p, next: %p",
1666
1886
                  nmb, pdo, fdo, fdo->attached, nmb->next_device);
1667
1887
 
1668
1888
        for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1669
 
                drv_obj->major_func[i] = IopPassIrpDown;
 
1889
                drv_obj->major_func[i] = IoPassIrpDown;
1670
1890
        drv_obj->major_func[IRP_MJ_PNP] = NdisDispatchPnp;
1671
1891
        drv_obj->major_func[IRP_MJ_POWER] = NdisDispatchPower;
1672
1892
        drv_obj->major_func[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
1673
1893
                NdisDispatchDeviceControl;
1674
 
        drv_obj->major_func[IRP_MJ_DEVICE_CONTROL] =
1675
 
                NdisDispatchDeviceControl;
 
1894
        drv_obj->major_func[IRP_MJ_DEVICE_CONTROL] = NdisDispatchDeviceControl;
1676
1895
        TRACEEXIT2(return STATUS_SUCCESS);
1677
1896
}
1678
1897