2 * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
21 #include <linux/inetdevice.h>
23 #include <linux/tcp.h>
24 #include <linux/udp.h>
28 /* Functions callable from the NDIS driver */
29 wstdcall NTSTATUS NdisDispatchDeviceControl(struct device_object *fdo,
31 wstdcall NTSTATUS NdisDispatchPnp(struct device_object *fdo, struct irp *irp);
32 wstdcall NTSTATUS NdisDispatchPower(struct device_object *fdo, struct irp *irp);
34 workqueue_struct_t *wrapndis_wq;
35 static struct nt_thread *wrapndis_worker_thread;
37 static int set_packet_filter(struct ndis_device *wnd,
39 static void add_iw_stats_timer(struct ndis_device *wnd);
40 static void del_iw_stats_timer(struct ndis_device *wnd);
41 static NDIS_STATUS ndis_start_device(struct ndis_device *wnd);
42 static int ndis_remove_device(struct ndis_device *wnd);
43 static void set_multicast_list(struct ndis_device *wnd);
44 static int ndis_net_dev_open(struct net_device *net_dev);
45 static int ndis_net_dev_close(struct net_device *net_dev);
48 NDIS_STATUS mp_reset(struct ndis_device *wnd)
52 BOOLEAN reset_address;
55 ENTER2("wnd: %p", wnd);
56 if (down_interruptible(&wnd->tx_ring_mutex))
57 EXIT3(return NDIS_STATUS_FAILURE);
58 if (down_interruptible(&wnd->ndis_req_mutex)) {
59 up(&wnd->tx_ring_mutex);
60 EXIT3(return NDIS_STATUS_FAILURE);
62 mp = &wnd->wd->driver->ndis_driver->mp;
63 prepare_wait_condition(wnd->ndis_req_task, wnd->ndis_req_done, 0);
64 WARNING("%s is being reset", wnd->net_dev->name);
65 irql = serialize_lock_irql(wnd);
66 assert_irql(_irql_ == DISPATCH_LEVEL);
67 res = LIN2WIN2(mp->reset, &reset_address, wnd->nmb->mp_ctx);
68 serialize_unlock_irql(wnd, irql);
70 TRACE2("%08X, %08X", res, reset_address);
71 if (res == NDIS_STATUS_PENDING) {
72 /* wait for NdisMResetComplete */
73 if (wait_condition((wnd->ndis_req_done > 0), 0,
74 TASK_INTERRUPTIBLE) < 0)
75 res = NDIS_STATUS_FAILURE;
77 res = wnd->ndis_req_status;
78 reset_address = wnd->ndis_req_done - 1;
80 TRACE2("%08X, %08X", res, reset_address);
82 up(&wnd->ndis_req_mutex);
83 if (res == NDIS_STATUS_SUCCESS && reset_address) {
84 set_packet_filter(wnd, wnd->packet_filter);
85 set_multicast_list(wnd);
87 up(&wnd->tx_ring_mutex);
91 /* MiniportRequest(Query/Set)Information */
92 NDIS_STATUS mp_request(enum ndis_request_type request,
93 struct ndis_device *wnd, ndis_oid oid,
94 void *buf, ULONG buflen, ULONG *written, ULONG *needed)
101 if (down_interruptible(&wnd->ndis_req_mutex))
102 EXIT3(return NDIS_STATUS_FAILURE);
107 mp = &wnd->wd->driver->ndis_driver->mp;
108 prepare_wait_condition(wnd->ndis_req_task, wnd->ndis_req_done, 0);
109 irql = serialize_lock_irql(wnd);
110 assert_irql(_irql_ == DISPATCH_LEVEL);
112 case NdisRequestQueryInformation:
113 TRACE2("%p, %08X, %p", mp->queryinfo, oid, wnd->nmb->mp_ctx);
114 res = LIN2WIN6(mp->queryinfo, wnd->nmb->mp_ctx, oid, buf,
115 buflen, written, needed);
117 case NdisRequestSetInformation:
118 TRACE2("%p, %08X, %p", mp->setinfo, oid, wnd->nmb->mp_ctx);
119 res = LIN2WIN6(mp->setinfo, wnd->nmb->mp_ctx, oid, buf,
120 buflen, written, needed);
123 WARNING("invalid request %d, %08X", request, oid);
124 res = NDIS_STATUS_NOT_SUPPORTED;
127 serialize_unlock_irql(wnd, irql);
128 TRACE2("%08X, %08X", res, oid);
129 if (res == NDIS_STATUS_PENDING) {
130 /* wait for NdisMQueryInformationComplete */
131 if (wait_condition((wnd->ndis_req_done > 0), 0,
132 TASK_INTERRUPTIBLE) < 0)
133 res = NDIS_STATUS_FAILURE;
135 res = wnd->ndis_req_status;
136 TRACE2("%08X, %08X", res, oid);
138 up(&wnd->ndis_req_mutex);
141 TRACE2("%08X, %d, %d, %d", res, buflen, *written,
147 /* MiniportPnPEventNotify */
148 static NDIS_STATUS mp_pnp_event(struct ndis_device *wnd,
149 enum ndis_device_pnp_event event,
154 ENTER1("%p, %d", wnd, event);
155 mp = &wnd->wd->driver->ndis_driver->mp;
156 if (!mp->pnp_event_notify) {
157 TRACE1("Windows driver %s doesn't support "
158 "MiniportPnpEventNotify", wnd->wd->driver->name);
159 return NDIS_STATUS_FAILURE;
161 /* RNDIS driver doesn't like to be notified if device is
163 if (!test_bit(HW_INITIALIZED, &wnd->wd->hw_status))
164 EXIT1(return NDIS_STATUS_SUCCESS);
166 case NdisDevicePnPEventSurpriseRemoved:
168 (wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK),
169 mp->pnp_event_notify);
170 if ((wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK) &&
171 !test_bit(HW_PRESENT, &wnd->wd->hw_status) &&
172 mp->pnp_event_notify) {
173 TRACE1("calling surprise_removed");
174 LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx,
175 NdisDevicePnPEventSurpriseRemoved, NULL, 0);
177 TRACE1("Windows driver %s doesn't support "
178 "MiniportPnpEventNotify for safe unplugging",
179 wnd->wd->driver->name);
180 return NDIS_STATUS_SUCCESS;
181 case NdisDevicePnPEventPowerProfileChanged:
183 power_profile = NdisPowerProfileAcOnLine;
184 LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx,
185 NdisDevicePnPEventPowerProfileChanged,
186 &power_profile, (ULONG)sizeof(power_profile));
187 return NDIS_STATUS_SUCCESS;
189 WARNING("event %d not yet implemented", event);
190 return NDIS_STATUS_SUCCESS;
194 /* MiniportInitialize */
195 static NDIS_STATUS mp_init(struct ndis_device *wnd)
197 NDIS_STATUS error_status, status;
199 enum ndis_medium medium_array[] = {NdisMedium802_3};
202 ENTER1("irql: %d", current_irql());
203 if (test_bit(HW_INITIALIZED, &wnd->wd->hw_status)) {
204 WARNING("device %p already initialized!", wnd);
205 return NDIS_STATUS_FAILURE;
208 if (!wnd->wd->driver->ndis_driver ||
209 !wnd->wd->driver->ndis_driver->mp.init) {
210 WARNING("assuming WDM (non-NDIS) driver");
211 EXIT1(return NDIS_STATUS_NOT_RECOGNIZED);
213 mp = &wnd->wd->driver->ndis_driver->mp;
214 status = LIN2WIN6(mp->init, &error_status, &medium_index, medium_array,
215 sizeof(medium_array) / sizeof(medium_array[0]),
217 TRACE1("init returns: %08X, irql: %d", status, current_irql());
218 if (status != NDIS_STATUS_SUCCESS) {
219 WARNING("couldn't initialize device: %08X", status);
220 EXIT1(return NDIS_STATUS_FAILURE);
223 /* Wait a little to let card power up otherwise ifup might
226 status = mp_pnp_event(wnd, NdisDevicePnPEventPowerProfileChanged,
227 NdisPowerProfileAcOnLine);
228 if (status != NDIS_STATUS_SUCCESS)
229 TRACE1("setting power failed: %08X", status);
230 set_bit(HW_INITIALIZED, &wnd->wd->hw_status);
231 /* the description about NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND is
232 * misleading/confusing */
233 status = mp_query(wnd, OID_PNP_CAPABILITIES,
234 &wnd->pnp_capa, sizeof(wnd->pnp_capa));
235 if (status == NDIS_STATUS_SUCCESS) {
236 TRACE1("%d, %d", wnd->pnp_capa.wakeup.min_magic_packet_wakeup,
237 wnd->pnp_capa.wakeup.min_pattern_wakeup);
238 wnd->attributes |= NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;
239 status = mp_query_int(wnd, OID_PNP_ENABLE_WAKE_UP,
241 TRACE1("%08X, %x", status, wnd->ndis_wolopts);
242 } else if (status == NDIS_STATUS_NOT_SUPPORTED)
243 wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;
244 TRACE1("%d", wnd->pnp_capa.wakeup.min_magic_packet_wakeup);
245 /* although some NDIS drivers support suspend, Linux kernel
246 * has issues with suspending USB devices */
247 if (wrap_is_usb_bus(wnd->wd->dev_bus)) {
248 wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;
249 wnd->ndis_wolopts = 0;
251 mp_set_int(wnd, OID_802_11_POWER_MODE, NDIS_POWER_OFF);
252 EXIT1(return NDIS_STATUS_SUCCESS);
256 static void mp_halt(struct ndis_device *wnd)
261 if (!test_and_clear_bit(HW_INITIALIZED, &wnd->wd->hw_status)) {
262 WARNING("device %p is not initialized - not halting", wnd);
266 del_iw_stats_timer(wnd);
267 if (wnd->physical_medium == NdisPhysicalMediumWirelessLan &&
268 wrap_is_pci_bus(wnd->wd->dev_bus)) {
269 up(&wnd->ndis_req_mutex);
270 disassociate(wnd, 0);
271 if (down_interruptible(&wnd->ndis_req_mutex))
272 WARNING("couldn't obtain ndis_req_mutex");
274 mp = &wnd->wd->driver->ndis_driver->mp;
275 TRACE1("halt: %p", mp->mp_halt);
276 LIN2WIN1(mp->mp_halt, wnd->nmb->mp_ctx);
277 /* if a driver doesn't call NdisMDeregisterInterrupt during
278 * halt, deregister it now */
279 if (wnd->mp_interrupt)
280 NdisMDeregisterInterrupt(wnd->mp_interrupt);
281 /* cancel any timers left by bugyy windows driver; also free
282 * the memory for timers */
284 struct nt_slist *slist;
285 struct wrap_timer *wrap_timer;
287 spin_lock_bh(&ntoskernel_lock);
288 if ((slist = wnd->wrap_timer_slist.next))
289 wnd->wrap_timer_slist.next = slist->next;
290 spin_unlock_bh(&ntoskernel_lock);
291 TIMERTRACE("%p", slist);
294 wrap_timer = container_of(slist, struct wrap_timer, slist);
295 wrap_timer->repeat = 0;
296 /* ktimer that this wrap_timer is associated to can't
297 * be touched, as it may have been freed by the driver
299 if (del_timer_sync(&wrap_timer->timer))
300 WARNING("Buggy Windows driver left timer %p "
301 "running", wrap_timer->nt_timer);
302 memset(wrap_timer, 0, sizeof(*wrap_timer));
308 static NDIS_STATUS mp_set_power_state(struct ndis_device *wnd,
309 enum ndis_power_state state)
314 if (state == NdisDeviceStateD0) {
315 status = NDIS_STATUS_SUCCESS;
316 up(&wnd->ndis_req_mutex);
317 if (test_and_clear_bit(HW_HALTED, &wnd->wd->hw_status)) {
318 status = mp_init(wnd);
319 if (status == NDIS_STATUS_SUCCESS) {
320 set_packet_filter(wnd, wnd->packet_filter);
321 set_multicast_list(wnd);
323 } else if (test_and_clear_bit(HW_SUSPENDED,
324 &wnd->wd->hw_status)) {
325 status = mp_set_int(wnd, OID_PNP_SET_POWER, state);
326 if (status != NDIS_STATUS_SUCCESS)
327 WARNING("%s: setting power to state %d failed? "
328 "%08X", wnd->net_dev->name, state,
331 return NDIS_STATUS_FAILURE;
333 if (wrap_is_pci_bus(wnd->wd->dev_bus)) {
334 pci_enable_wake(wnd->wd->pci.pdev, PCI_D3hot, 0);
335 pci_enable_wake(wnd->wd->pci.pdev, PCI_D3cold, 0);
337 if (status == NDIS_STATUS_SUCCESS) {
338 up(&wnd->tx_ring_mutex);
339 netif_device_attach(wnd->net_dev);
341 add_iw_stats_timer(wnd);
343 WARNING("%s: couldn't set power to state %d; device not"
344 " resumed", wnd->net_dev->name, state);
345 EXIT1(return status);
347 if (down_interruptible(&wnd->tx_ring_mutex))
348 EXIT1(return NDIS_STATUS_FAILURE);
349 netif_device_detach(wnd->net_dev);
351 del_iw_stats_timer(wnd);
352 status = NDIS_STATUS_NOT_SUPPORTED;
353 if (wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND) {
354 status = mp_set_int(wnd, OID_PNP_ENABLE_WAKE_UP,
356 TRACE2("0x%x, 0x%x", status, wnd->ndis_wolopts);
357 if (status == NDIS_STATUS_SUCCESS) {
358 if (wnd->ndis_wolopts)
359 wnd->wd->pci.wake_state =
362 wnd->wd->pci.wake_state =
363 PowerDeviceUnspecified;
365 WARNING("couldn't set wake-on-lan options: "
366 "0x%x, %08X", wnd->ndis_wolopts, status);
367 status = mp_set_int(wnd, OID_PNP_SET_POWER, state);
368 if (status == NDIS_STATUS_SUCCESS)
369 set_bit(HW_SUSPENDED, &wnd->wd->hw_status);
371 WARNING("suspend failed: %08X", status);
373 if (status != NDIS_STATUS_SUCCESS) {
374 WARNING("%s does not support power management; "
375 "halting the device", wnd->net_dev->name);
377 set_bit(HW_HALTED, &wnd->wd->hw_status);
378 status = STATUS_SUCCESS;
380 if (down_interruptible(&wnd->ndis_req_mutex))
381 WARNING("couldn't lock ndis_req_mutex");
382 EXIT1(return status);
386 static int ndis_set_mac_address(struct net_device *dev, void *p)
388 struct ndis_device *wnd = netdev_priv(dev);
389 struct sockaddr *addr = p;
390 struct ndis_configuration_parameter param;
391 struct unicode_string key;
392 struct ansi_string ansi;
394 unsigned char mac_string[2 * ETH_ALEN + 1];
397 memcpy(mac, addr->sa_data, sizeof(mac));
398 memset(mac_string, 0, sizeof(mac_string));
399 res = snprintf(mac_string, sizeof(mac_string), MACSTR, MAC2STR(mac));
400 if (res != (sizeof(mac_string) - 1))
401 EXIT1(return -EINVAL);
402 TRACE1("new mac: %s", mac_string);
404 RtlInitAnsiString(&ansi, mac_string);
405 if (RtlAnsiStringToUnicodeString(¶m.data.string, &ansi,
406 TRUE) != STATUS_SUCCESS)
407 EXIT1(return -EINVAL);
409 param.type = NdisParameterString;
410 RtlInitAnsiString(&ansi, "NetworkAddress");
411 if (RtlAnsiStringToUnicodeString(&key, &ansi, TRUE) != STATUS_SUCCESS) {
412 RtlFreeUnicodeString(¶m.data.string);
413 EXIT1(return -EINVAL);
415 NdisWriteConfiguration(&res, wnd->nmb, &key, ¶m);
416 RtlFreeUnicodeString(&key);
417 RtlFreeUnicodeString(¶m.data.string);
419 if (res != NDIS_STATUS_SUCCESS)
420 EXIT1(return -EFAULT);
421 if (ndis_reinit(wnd) == NDIS_STATUS_SUCCESS) {
422 res = mp_query(wnd, OID_802_3_CURRENT_ADDRESS,
424 if (res == NDIS_STATUS_SUCCESS) {
425 TRACE1("mac:" MACSTRSEP, MAC2STR(mac));
426 memcpy(dev->dev_addr, mac, sizeof(mac));
428 ERROR("couldn't get mac address: %08X", res);
433 static int setup_tx_sg_list(struct ndis_device *wnd, struct sk_buff *skb,
434 struct ndis_packet_oob_data *oob_data)
436 struct ndis_sg_element *sg_element;
437 struct ndis_sg_list *sg_list;
440 ENTER3("%p, %d", skb, skb_shinfo(skb)->nr_frags);
441 if (skb_shinfo(skb)->nr_frags <= 1) {
442 sg_element = &oob_data->wrap_tx_sg_list.elements[0];
443 sg_element->address =
444 PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, skb->data,
445 skb->len, PCI_DMA_TODEVICE);
446 sg_element->length = skb->len;
447 oob_data->wrap_tx_sg_list.nent = 1;
448 oob_data->ext.info[ScatterGatherListPacketInfo] =
449 &oob_data->wrap_tx_sg_list;
450 TRACE3("%Lx, %u", sg_element->address, sg_element->length);
453 sg_list = kmalloc(sizeof(*sg_list) +
454 (skb_shinfo(skb)->nr_frags + 1) * sizeof(*sg_element),
458 sg_list->nent = skb_shinfo(skb)->nr_frags + 1;
459 TRACE3("%p, %d", sg_list, sg_list->nent);
460 sg_element = sg_list->elements;
461 sg_element->length = skb_headlen(skb);
462 sg_element->address =
463 PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, skb->data,
464 skb_headlen(skb), PCI_DMA_TODEVICE);
465 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
466 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
468 sg_element->length = frag->size;
469 sg_element->address =
470 pci_map_page(wnd->wd->pci.pdev, frag->page,
471 frag->page_offset, frag->size,
473 TRACE3("%Lx, %u", sg_element->address, sg_element->length);
475 oob_data->ext.info[ScatterGatherListPacketInfo] = sg_list;
479 static void free_tx_sg_list(struct ndis_device *wnd,
480 struct ndis_packet_oob_data *oob_data)
483 struct ndis_sg_element *sg_element;
484 struct ndis_sg_list *sg_list =
485 oob_data->ext.info[ScatterGatherListPacketInfo];
486 sg_element = sg_list->elements;
487 TRACE3("%p, %d", sg_list, sg_list->nent);
488 PCI_DMA_UNMAP_SINGLE(wnd->wd->pci.pdev, sg_element->address,
489 sg_element->length, PCI_DMA_TODEVICE);
490 if (sg_list->nent == 1)
492 for (i = 1; i < sg_list->nent; i++, sg_element++) {
493 TRACE3("%Lx, %u", sg_element->address, sg_element->length);
494 pci_unmap_page(wnd->wd->pci.pdev, sg_element->address,
495 sg_element->length, PCI_DMA_TODEVICE);
497 TRACE3("%p", sg_list);
501 static struct ndis_packet *alloc_tx_packet(struct ndis_device *wnd,
504 struct ndis_packet *packet;
506 struct ndis_packet_oob_data *oob_data;
509 NdisAllocatePacket(&status, &packet, wnd->tx_packet_pool);
510 if (status != NDIS_STATUS_SUCCESS)
512 NdisAllocateBuffer(&status, &buffer, wnd->tx_buffer_pool,
513 skb->data, skb->len);
514 if (status != NDIS_STATUS_SUCCESS) {
515 NdisFreePacket(packet);
518 packet->private.buffer_head = buffer;
519 packet->private.buffer_tail = buffer;
521 oob_data = NDIS_PACKET_OOB_DATA(packet);
522 oob_data->tx_skb = skb;
523 if (wnd->sg_dma_size) {
524 if (setup_tx_sg_list(wnd, skb, oob_data)) {
525 NdisFreeBuffer(buffer);
526 NdisFreePacket(packet);
530 if (skb->ip_summed == CHECKSUM_PARTIAL) {
531 struct ndis_tcp_ip_checksum_packet_info csum;
533 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21)
534 protocol = ntohs(skb->protocol);
536 protocol = skb->nh.iph->protocol;
540 if (protocol == IPPROTO_TCP)
542 else if (protocol == IPPROTO_UDP)
545 packet->private.flags |= NDIS_PROTOCOL_ID_TCP_IP;
546 oob_data->ext.info[TcpIpChecksumPacketInfo] =
547 (void *)(ULONG_PTR)csum.value;
550 dump_bytes(__func__, skb->data, skb->len);
552 TRACE4("%p, %p, %p", packet, buffer, skb);
556 void free_tx_packet(struct ndis_device *wnd, struct ndis_packet *packet,
560 struct ndis_packet_oob_data *oob_data;
562 struct ndis_packet_pool *pool;
564 assert_irql(_irql_ <= DISPATCH_LEVEL);
565 assert(packet->private.packet_flags);
566 oob_data = NDIS_PACKET_OOB_DATA(packet);
567 skb = oob_data->tx_skb;
568 buffer = packet->private.buffer_head;
569 TRACE4("%p, %p, %p, %08X", packet, buffer, skb, status);
570 if (status == NDIS_STATUS_SUCCESS) {
571 pre_atomic_add(wnd->net_stats.tx_bytes, packet->private.len);
572 atomic_inc_var(wnd->net_stats.tx_packets);
574 TRACE1("packet dropped: %08X", status);
575 atomic_inc_var(wnd->net_stats.tx_dropped);
577 if (wnd->sg_dma_size)
578 free_tx_sg_list(wnd, oob_data);
579 NdisFreeBuffer(buffer);
580 dev_kfree_skb_any(skb);
581 pool = packet->private.pool;
582 NdisFreePacket(packet);
583 if (netif_queue_stopped(wnd->net_dev) &&
584 ((pool->max_descr - pool->num_used_descr) >=
585 (wnd->max_tx_packets / 4))) {
586 set_bit(NETIF_WAKEQ, &wnd->ndis_pending_work);
587 schedule_wrapndis_work(&wnd->ndis_work);
592 /* MiniportSend and MiniportSendPackets */
593 /* this function is called holding tx_ring_mutex. start and n are such
594 * that start + n < TX_RING_SIZE; i.e., packets don't wrap around
596 static u8 mp_tx_packets(struct ndis_device *wnd, u8 start, u8 n)
600 struct ndis_packet *packet;
604 ENTER3("%d, %d", start, n);
605 mp = &wnd->wd->driver->ndis_driver->mp;
606 if (mp->send_packets) {
607 if (deserialized_driver(wnd)) {
608 LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx,
609 &wnd->tx_ring[start], n);
612 irql = serialize_lock_irql(wnd);
613 LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx,
614 &wnd->tx_ring[start], n);
615 serialize_unlock_irql(wnd, irql);
616 for (sent = 0; sent < n && wnd->tx_ok; sent++) {
617 struct ndis_packet_oob_data *oob_data;
618 packet = wnd->tx_ring[start + sent];
619 oob_data = NDIS_PACKET_OOB_DATA(packet);
621 xchg(&oob_data->status,
622 NDIS_STATUS_NOT_RECOGNIZED))) {
623 case NDIS_STATUS_SUCCESS:
624 free_tx_packet(wnd, packet,
625 NDIS_STATUS_SUCCESS);
627 case NDIS_STATUS_PENDING:
629 case NDIS_STATUS_RESOURCES:
631 /* resubmit this packet and
632 * the rest when resources
633 * become available */
636 case NDIS_STATUS_FAILURE:
637 free_tx_packet(wnd, packet,
638 NDIS_STATUS_FAILURE);
641 ERROR("%p: invalid status: %08X",
643 free_tx_packet(wnd, packet,
647 TRACE3("%p, %d", packet, res);
650 TRACE3("sent: %d(%d)", sent, n);
652 for (sent = 0; sent < n && wnd->tx_ok; sent++) {
653 struct ndis_packet_oob_data *oob_data;
654 packet = wnd->tx_ring[start + sent];
655 oob_data = NDIS_PACKET_OOB_DATA(packet);
656 oob_data->status = NDIS_STATUS_NOT_RECOGNIZED;
657 irql = serialize_lock_irql(wnd);
658 res = LIN2WIN3(mp->send, wnd->nmb->mp_ctx,
659 packet, packet->private.flags);
660 serialize_unlock_irql(wnd, irql);
662 case NDIS_STATUS_SUCCESS:
663 free_tx_packet(wnd, packet, res);
665 case NDIS_STATUS_PENDING:
667 case NDIS_STATUS_RESOURCES:
669 /* resend this packet when resources
670 * become available */
673 case NDIS_STATUS_FAILURE:
674 free_tx_packet(wnd, packet, res);
677 ERROR("packet %p: invalid status: %08X",
686 static void tx_worker(worker_param_t param)
688 struct ndis_device *wnd;
691 wnd = worker_param_data(param, struct ndis_device, tx_work);
692 ENTER3("tx_ok %d", wnd->tx_ok);
694 if (down_interruptible(&wnd->tx_ring_mutex))
696 spin_lock_bh(&wnd->tx_ring_lock);
697 n = wnd->tx_ring_end - wnd->tx_ring_start;
698 TRACE3("%d, %d, %d", wnd->tx_ring_start, wnd->tx_ring_end, n);
699 /* end == start if either ring is empty or full; in
700 * the latter case is_tx_ring_full is set */
702 if (wnd->is_tx_ring_full)
703 n = TX_RING_SIZE - wnd->tx_ring_start;
705 spin_unlock_bh(&wnd->tx_ring_lock);
706 up(&wnd->tx_ring_mutex);
710 n = TX_RING_SIZE - wnd->tx_ring_start;
711 spin_unlock_bh(&wnd->tx_ring_lock);
712 if (unlikely(n > wnd->max_tx_packets))
713 n = wnd->max_tx_packets;
714 n = mp_tx_packets(wnd, wnd->tx_ring_start, n);
716 wnd->net_dev->trans_start = jiffies;
718 (wnd->tx_ring_start + n) % TX_RING_SIZE;
719 wnd->is_tx_ring_full = 0;
721 up(&wnd->tx_ring_mutex);
722 TRACE3("%d, %d, %d", wnd->tx_ring_start, wnd->tx_ring_end, n);
727 static int tx_skbuff(struct sk_buff *skb, struct net_device *dev)
729 struct ndis_device *wnd = netdev_priv(dev);
730 struct ndis_packet *packet;
732 packet = alloc_tx_packet(wnd, skb);
734 TRACE2("couldn't allocate packet");
736 netif_stop_queue(dev);
737 netif_tx_unlock(dev);
738 return NETDEV_TX_BUSY;
740 spin_lock(&wnd->tx_ring_lock);
741 wnd->tx_ring[wnd->tx_ring_end++] = packet;
742 if (wnd->tx_ring_end == TX_RING_SIZE)
743 wnd->tx_ring_end = 0;
744 if (wnd->tx_ring_end == wnd->tx_ring_start) {
746 wnd->is_tx_ring_full = 1;
747 netif_stop_queue(dev);
748 netif_tx_unlock(dev);
750 spin_unlock(&wnd->tx_ring_lock);
751 TRACE4("ring: %d, %d", wnd->tx_ring_start, wnd->tx_ring_end);
752 schedule_wrapndis_work(&wnd->tx_work);
756 static int set_packet_filter(struct ndis_device *wnd, ULONG packet_filter)
761 res = mp_set_int(wnd, OID_GEN_CURRENT_PACKET_FILTER,
763 if (res == NDIS_STATUS_SUCCESS)
765 TRACE2("couldn't set filter 0x%08x", packet_filter);
766 /* NDIS_PACKET_TYPE_PROMISCUOUS may not work with 802.11 */
767 if (packet_filter & NDIS_PACKET_TYPE_PROMISCUOUS) {
768 packet_filter &= ~NDIS_PACKET_TYPE_PROMISCUOUS;
771 if (packet_filter & NDIS_PACKET_TYPE_ALL_LOCAL) {
772 packet_filter &= ~NDIS_PACKET_TYPE_ALL_LOCAL;
775 if (packet_filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) {
776 packet_filter &= ~NDIS_PACKET_TYPE_ALL_FUNCTIONAL;
779 if (packet_filter & NDIS_PACKET_TYPE_MULTICAST) {
780 packet_filter &= ~NDIS_PACKET_TYPE_MULTICAST;
781 packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
784 if (packet_filter & NDIS_PACKET_TYPE_ALL_MULTICAST) {
785 packet_filter &= ~NDIS_PACKET_TYPE_ALL_MULTICAST;
791 wnd->packet_filter = packet_filter;
792 res = mp_query_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, &packet_filter);
793 if (packet_filter != wnd->packet_filter) {
794 WARNING("filter not set: 0x%08x, 0x%08x",
795 packet_filter, wnd->packet_filter);
796 wnd->packet_filter = packet_filter;
798 if (wnd->packet_filter)
804 void set_media_state(struct ndis_device *wnd, enum ndis_media_state state)
806 ENTER2("state: 0x%x", state);
807 if (state == NdisMediaStateConnected) {
808 netif_carrier_on(wnd->net_dev);
810 if (netif_queue_stopped(wnd->net_dev))
811 netif_wake_queue(wnd->net_dev);
812 if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) {
813 set_bit(LINK_STATUS_ON, &wnd->ndis_pending_work);
814 schedule_wrapndis_work(&wnd->ndis_work);
816 } else if (state == NdisMediaStateDisconnected) {
817 netif_carrier_off(wnd->net_dev);
818 netif_stop_queue(wnd->net_dev);
820 if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) {
821 memset(&wnd->essid, 0, sizeof(wnd->essid));
822 set_bit(LINK_STATUS_OFF, &wnd->ndis_pending_work);
823 schedule_wrapndis_work(&wnd->ndis_work);
826 WARNING("invalid media state: 0x%x", state);
830 static int ndis_net_dev_open(struct net_device *net_dev)
832 ENTER1("%p", netdev_priv(net_dev));
833 netif_start_queue(net_dev);
834 netif_poll_enable(net_dev);
838 static int ndis_net_dev_close(struct net_device *net_dev)
840 ENTER1("%p", netdev_priv(net_dev));
841 netif_poll_disable(net_dev);
842 netif_tx_disable(net_dev);
846 static int ndis_change_mtu(struct net_device *net_dev, int mtu)
848 struct ndis_device *wnd = netdev_priv(net_dev);
853 if (mp_query_int(wnd, OID_GEN_MAXIMUM_TOTAL_SIZE, &max) !=
860 if (mtu + ETH_HLEN > max)
866 #ifdef CONFIG_NET_POLL_CONTROLLER
867 static void ndis_poll_controller(struct net_device *dev)
869 struct ndis_device *wnd = netdev_priv(dev);
871 disable_irq(dev->irq);
872 ndis_isr(wnd->mp_interrupt->kinterrupt, wnd->mp_interrupt);
873 enable_irq(dev->irq);
877 /* called from BH context */
878 static struct net_device_stats *ndis_get_stats(struct net_device *dev)
880 struct ndis_device *wnd = netdev_priv(dev);
881 return &wnd->net_stats;
884 /* called from BH context */
885 static void ndis_set_multicast_list(struct net_device *dev)
887 struct ndis_device *wnd = netdev_priv(dev);
888 set_bit(SET_MULTICAST_LIST, &wnd->ndis_pending_work);
889 schedule_wrapndis_work(&wnd->ndis_work);
892 /* called from BH context */
893 struct iw_statistics *get_iw_stats(struct net_device *dev)
895 struct ndis_device *wnd = netdev_priv(dev);
896 return &wnd->iw_stats;
899 static void update_iw_stats(struct ndis_device *wnd)
901 struct iw_statistics *iw_stats = &wnd->iw_stats;
902 struct ndis_wireless_stats ndis_stats;
908 if (wnd->iw_stats_enabled == FALSE || !netif_carrier_ok(wnd->net_dev)) {
909 memset(iw_stats, 0, sizeof(*iw_stats));
912 res = mp_query(wnd, OID_802_11_RSSI, &rssi, sizeof(rssi));
913 if (res == NDIS_STATUS_SUCCESS)
914 iw_stats->qual.level = rssi;
916 qual = 100 * (rssi - WL_NOISE) / (WL_SIGMAX - WL_NOISE);
922 iw_stats->qual.noise = WL_NOISE;
923 iw_stats->qual.qual = qual;
925 res = mp_query(wnd, OID_802_11_STATISTICS,
926 &ndis_stats, sizeof(ndis_stats));
927 if (res != NDIS_STATUS_SUCCESS)
929 iw_stats->discard.retries = (unsigned long)ndis_stats.retry +
930 (unsigned long)ndis_stats.multi_retry;
931 iw_stats->discard.misc = (unsigned long)ndis_stats.fcs_err +
932 (unsigned long)ndis_stats.rtss_fail +
933 (unsigned long)ndis_stats.ack_fail +
934 (unsigned long)ndis_stats.frame_dup;
939 static void set_multicast_list(struct ndis_device *wnd)
941 struct net_device *net_dev;
946 net_dev = wnd->net_dev;
947 packet_filter = wnd->packet_filter;
948 mc_count = netdev_mc_count(net_dev);
950 TRACE2("0x%08x", packet_filter);
951 if (net_dev->flags & IFF_PROMISC) {
952 packet_filter |= NDIS_PACKET_TYPE_PROMISCUOUS |
953 NDIS_PACKET_TYPE_ALL_LOCAL;
954 } else if (net_dev->flags & IFF_ALLMULTI ||
955 mc_count > wnd->multicast_size) {
956 packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
957 TRACE2("0x%08x", packet_filter);
958 } else if (mc_count > 0) {
961 struct netdev_hw_addr *ha;
962 size = min(wnd->multicast_size, mc_count);
963 TRACE2("%d, %d", wnd->multicast_size, mc_count);
964 buf = kmalloc(size * ETH_ALEN, GFP_KERNEL);
966 WARNING("couldn't allocate memory");
970 netdev_for_each_mc_addr(ha, net_dev) {
973 if (net_dev->addr_len != ETH_ALEN)
975 memcpy(buf + i * ETH_ALEN, ha->addr, ETH_ALEN);
976 TRACE2(MACSTRSEP, MAC2STR(ha->addr));
979 res = mp_set(wnd, OID_802_3_MULTICAST_LIST, buf, i * ETH_ALEN);
980 if (res == NDIS_STATUS_SUCCESS && i > 0)
981 packet_filter |= NDIS_PACKET_TYPE_MULTICAST;
983 packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
986 TRACE2("0x%08x", packet_filter);
987 res = set_packet_filter(wnd, packet_filter);
989 TRACE1("couldn't set packet filter (%08X)", res);
993 static void link_status_off(struct ndis_device *wnd)
995 #ifdef CONFIG_WIRELESS_EXT
996 union iwreq_data wrqu;
998 memset(&wrqu, 0, sizeof(wrqu));
999 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
1000 wireless_send_event(wnd->net_dev, SIOCGIWAP, &wrqu, NULL);
1005 static void link_status_on(struct ndis_device *wnd)
1007 #ifdef CONFIG_WIRELESS_EXT
1008 struct ndis_assoc_info *ndis_assoc_info;
1009 union iwreq_data wrqu;
1011 const int assoc_size = sizeof(*ndis_assoc_info) + IW_CUSTOM_MAX + 32;
1015 #ifdef CONFIG_WIRELESS_EXT
1016 memset(&wrqu, 0, sizeof(wrqu));
1017 ndis_assoc_info = kzalloc(assoc_size, GFP_KERNEL);
1018 if (!ndis_assoc_info) {
1019 ERROR("couldn't allocate memory");
1020 goto send_assoc_event;
1022 res = mp_query(wnd, OID_802_11_ASSOCIATION_INFORMATION,
1023 ndis_assoc_info, assoc_size);
1025 TRACE2("query assoc_info failed (%08X)", res);
1026 kfree(ndis_assoc_info);
1027 goto send_assoc_event;
1029 TRACE2("%u, 0x%x, %u, 0x%x, %u", ndis_assoc_info->length,
1030 ndis_assoc_info->req_ies, ndis_assoc_info->req_ie_length,
1031 ndis_assoc_info->resp_ies, ndis_assoc_info->resp_ie_length);
1032 if (ndis_assoc_info->req_ie_length > 0) {
1033 wrqu.data.length = ndis_assoc_info->req_ie_length;
1034 wireless_send_event(wnd->net_dev, IWEVASSOCREQIE, &wrqu,
1035 ((char *)ndis_assoc_info) +
1036 ndis_assoc_info->offset_req_ies);
1038 if (ndis_assoc_info->resp_ie_length > 0) {
1039 wrqu.data.length = ndis_assoc_info->resp_ie_length;
1040 wireless_send_event(wnd->net_dev, IWEVASSOCRESPIE, &wrqu,
1041 ((char *)ndis_assoc_info) +
1042 ndis_assoc_info->offset_resp_ies);
1044 kfree(ndis_assoc_info);
1047 get_ap_address(wnd, wrqu.ap_addr.sa_data);
1048 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
1049 TRACE2(MACSTRSEP, MAC2STR(wrqu.ap_addr.sa_data));
1050 wireless_send_event(wnd->net_dev, SIOCGIWAP, &wrqu, NULL);
1055 static void iw_stats_timer_proc(unsigned long data)
1057 struct ndis_device *wnd = (struct ndis_device *)data;
1059 ENTER2("%d", wnd->iw_stats_interval);
1060 if (wnd->iw_stats_interval > 0) {
1061 set_bit(COLLECT_IW_STATS, &wnd->ndis_pending_work);
1062 schedule_wrapndis_work(&wnd->ndis_work);
1064 mod_timer(&wnd->iw_stats_timer, jiffies + wnd->iw_stats_interval);
1067 static void add_iw_stats_timer(struct ndis_device *wnd)
1069 if (wnd->physical_medium != NdisPhysicalMediumWirelessLan)
1071 if (wnd->iw_stats_interval < 0)
1072 wnd->iw_stats_interval *= -1;
1073 wnd->iw_stats_timer.data = (unsigned long)wnd;
1074 wnd->iw_stats_timer.function = iw_stats_timer_proc;
1075 mod_timer(&wnd->iw_stats_timer, jiffies + wnd->iw_stats_interval);
1078 static void del_iw_stats_timer(struct ndis_device *wnd)
1080 ENTER2("%d", wnd->iw_stats_interval);
1081 wnd->iw_stats_interval *= -1;
1082 del_timer_sync(&wnd->iw_stats_timer);
1086 static void hangcheck_proc(unsigned long data)
1088 struct ndis_device *wnd = (struct ndis_device *)data;
1090 ENTER3("%d", wnd->hangcheck_interval);
1091 if (wnd->hangcheck_interval > 0) {
1092 set_bit(HANGCHECK, &wnd->ndis_pending_work);
1093 schedule_wrapndis_work(&wnd->ndis_work);
1095 mod_timer(&wnd->hangcheck_timer, jiffies + wnd->hangcheck_interval);
1099 void hangcheck_add(struct ndis_device *wnd)
1101 if (!wnd->wd->driver->ndis_driver->mp.hangcheck ||
1102 hangcheck_interval < 0)
1105 if (hangcheck_interval > 0)
1106 wnd->hangcheck_interval = hangcheck_interval * HZ;
1107 if (wnd->hangcheck_interval < 0)
1108 wnd->hangcheck_interval *= -1;
1109 wnd->hangcheck_timer.data = (unsigned long)wnd;
1110 wnd->hangcheck_timer.function = hangcheck_proc;
1111 mod_timer(&wnd->hangcheck_timer, jiffies + wnd->hangcheck_interval);
1115 void hangcheck_del(struct ndis_device *wnd)
1117 ENTER2("%d", wnd->hangcheck_interval);
1118 if (wnd->hangcheck_interval > 0)
1119 wnd->hangcheck_interval *= -1;
1120 del_timer_sync(&wnd->hangcheck_timer);
1124 /* worker procedure to take care of setting/checking various states */
1125 static void ndis_worker(worker_param_t param)
1127 struct ndis_device *wnd;
1129 wnd = worker_param_data(param, struct ndis_device, ndis_work);
1130 WORKTRACE("0x%lx", wnd->ndis_pending_work);
1132 if (test_and_clear_bit(NETIF_WAKEQ, &wnd->ndis_pending_work)) {
1133 netif_tx_lock_bh(wnd->net_dev);
1134 netif_wake_queue(wnd->net_dev);
1135 netif_tx_unlock_bh(wnd->net_dev);
1138 if (test_and_clear_bit(LINK_STATUS_OFF, &wnd->ndis_pending_work))
1139 link_status_off(wnd);
1141 if (test_and_clear_bit(LINK_STATUS_ON, &wnd->ndis_pending_work))
1142 link_status_on(wnd);
1144 if (test_and_clear_bit(COLLECT_IW_STATS, &wnd->ndis_pending_work))
1145 update_iw_stats(wnd);
1147 if (test_and_clear_bit(SET_MULTICAST_LIST,
1148 &wnd->ndis_pending_work))
1149 set_multicast_list(wnd);
1151 if (test_and_clear_bit(HANGCHECK, &wnd->ndis_pending_work)) {
1152 struct miniport *mp;
1156 mp = &wnd->wd->driver->ndis_driver->mp;
1157 irql = serialize_lock_irql(wnd);
1158 reset = LIN2WIN1(mp->hangcheck, wnd->nmb->mp_ctx);
1159 serialize_unlock_irql(wnd, irql);
1161 TRACE2("%s needs reset", wnd->net_dev->name);
1168 NDIS_STATUS ndis_reinit(struct ndis_device *wnd)
1172 wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND;
1173 status = mp_set_power_state(wnd, NdisDeviceStateD3);
1174 if (status != NDIS_STATUS_SUCCESS) {
1175 ERROR("halting device %s failed: %08X", wnd->net_dev->name,
1179 status = mp_set_power_state(wnd, NdisDeviceStateD0);
1180 if (status != NDIS_STATUS_SUCCESS)
1181 ERROR("starting device %s failed: %08X", wnd->net_dev->name,
1186 static void get_encryption_capa(struct ndis_device *wnd, char *buf,
1191 struct ndis_assoc_info ndis_assoc_info;
1192 struct ndis_add_key ndis_key;
1193 struct ndis_capability *c;
1196 /* set network type to g, b, or a, in that order */
1197 res = mp_query(wnd, OID_802_11_NETWORK_TYPES_SUPPORTED, buf, buf_len);
1198 if (res == NDIS_STATUS_SUCCESS) {
1199 struct network_type_list *net_types;
1200 unsigned long types = 0;
1201 net_types = (typeof(net_types))buf;
1202 for (i = 0; i < net_types->num; i++) {
1203 TRACE2("%d", net_types->types[i]);
1204 set_bit(net_types->types[i], &types);
1206 if (types & Ndis802_11OFDM24)
1207 mode = Ndis802_11OFDM24;
1208 else if (types & Ndis802_11DS)
1209 mode = Ndis802_11DS;
1210 else if (types & Ndis802_11OFDM5)
1211 mode = Ndis802_11OFDM5;
1213 mode = Ndis802_11DS;
1214 mp_set_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE, mode);
1216 /* check if WEP is supported */
1217 if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104,
1218 IW_AUTH_CIPHER_NONE) == 0 &&
1219 get_ndis_encr_mode(wnd) == Ndis802_11Encryption1KeyAbsent)
1220 set_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr);
1222 /* check if WPA is supported */
1223 if (set_ndis_auth_mode(wnd, Ndis802_11AuthModeWPA) == 0 &&
1224 get_ndis_auth_mode(wnd) == Ndis802_11AuthModeWPA)
1225 set_bit(Ndis802_11AuthModeWPA, &wnd->capa.encr);
1229 if (set_ndis_auth_mode(wnd, Ndis802_11AuthModeWPAPSK) == 0 &&
1230 get_ndis_auth_mode(wnd) == Ndis802_11AuthModeWPAPSK)
1231 set_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.encr);
1233 /* check for highest encryption */
1235 if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_CCMP,
1236 IW_AUTH_CIPHER_NONE) == 0 &&
1237 (i = get_ndis_encr_mode(wnd)) > 0 &&
1238 (i == Ndis802_11Encryption3KeyAbsent ||
1239 i == Ndis802_11Encryption3Enabled))
1240 mode = Ndis802_11Encryption3Enabled;
1241 else if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_TKIP,
1242 IW_AUTH_CIPHER_NONE) == 0 &&
1243 (i = get_ndis_encr_mode(wnd)) > 0 &&
1244 (i == Ndis802_11Encryption2KeyAbsent ||
1245 i == Ndis802_11Encryption2Enabled))
1246 mode = Ndis802_11Encryption2Enabled;
1247 else if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104,
1248 IW_AUTH_CIPHER_NONE) == 0 &&
1249 (i = get_ndis_encr_mode(wnd)) > 0 &&
1250 (i == Ndis802_11Encryption1KeyAbsent ||
1251 i == Ndis802_11Encryption1Enabled))
1252 mode = Ndis802_11Encryption1Enabled;
1254 TRACE1("mode: %d", mode);
1257 set_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr);
1258 if (mode == Ndis802_11Encryption1Enabled)
1261 ndis_key.length = 32;
1262 ndis_key.index = 0xC0000001;
1263 ndis_key.struct_size = sizeof(ndis_key);
1264 res = mp_set(wnd, OID_802_11_ADD_KEY, &ndis_key, ndis_key.struct_size);
1265 TRACE2("%08X, %lu", res, (unsigned long)sizeof(ndis_key));
1266 if (res && res != NDIS_STATUS_INVALID_DATA)
1268 res = mp_query(wnd, OID_802_11_ASSOCIATION_INFORMATION,
1269 &ndis_assoc_info, sizeof(ndis_assoc_info));
1270 TRACE1("%08X", res);
1271 if (res == NDIS_STATUS_NOT_SUPPORTED)
1274 set_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr);
1275 if (mode == Ndis802_11Encryption3Enabled)
1276 set_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr);
1277 /* not all drivers support OID_802_11_CAPABILITY, so we don't
1278 * know for sure if driver support WPA or WPAPSK; assume
1280 set_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.auth);
1281 wnd->max_pmkids = 1;
1283 memset(buf, 0, buf_len);
1284 c = (struct ndis_capability *)buf;
1285 res = mp_query(wnd, OID_802_11_CAPABILITY, buf, buf_len);
1286 if (!(res == NDIS_STATUS_SUCCESS && c->version == 2))
1288 wnd->max_pmkids = c->num_PMKIDs;
1290 for (i = 0; i < c->num_auth_encr_pair; i++) {
1291 struct ndis_auth_encr_pair *ae;
1293 ae = &c->auth_encr_pair[i];
1294 if ((char *)(ae + 1) > buf + buf_len)
1296 switch (ae->auth_mode) {
1297 case Ndis802_11AuthModeOpen:
1298 case Ndis802_11AuthModeShared:
1299 case Ndis802_11AuthModeWPA:
1300 case Ndis802_11AuthModeWPAPSK:
1301 case Ndis802_11AuthModeWPANone:
1302 case Ndis802_11AuthModeWPA2:
1303 case Ndis802_11AuthModeWPA2PSK:
1304 set_bit(ae->auth_mode, &wnd->capa.auth);
1307 WARNING("unknown auth_mode: %d", ae->auth_mode);
1310 switch (ae->encr_mode) {
1311 case Ndis802_11EncryptionDisabled:
1312 case Ndis802_11Encryption1Enabled:
1313 case Ndis802_11Encryption2Enabled:
1314 case Ndis802_11Encryption3Enabled:
1315 set_bit(ae->encr_mode, &wnd->capa.encr);
1318 WARNING("unknown encr_mode: %d", ae->encr_mode);
1325 wstdcall NTSTATUS NdisDispatchDeviceControl(struct device_object *fdo,
1328 struct ndis_device *wnd;
1330 TRACE3("fdo: %p", fdo);
1331 /* for now, we don't have anything intresting here, so pass it
1332 * down to bus driver */
1333 wnd = fdo->reserved;
1334 return IoPassIrpDown(wnd->nmb->pdo, irp);
1336 WIN_FUNC_DECL(NdisDispatchDeviceControl,2)
1338 wstdcall NTSTATUS NdisDispatchPower(struct device_object *fdo, struct irp *irp)
1340 struct io_stack_location *irp_sl;
1341 struct ndis_device *wnd;
1342 enum ndis_power_state state;
1344 NDIS_STATUS ndis_status;
1346 irp_sl = IoGetCurrentIrpStackLocation(irp);
1347 wnd = fdo->reserved;
1348 IOTRACE("fdo: %p, fn: %d:%d, wnd: %p", fdo, irp_sl->major_fn,
1349 irp_sl->minor_fn, wnd);
1350 if ((irp_sl->params.power.type == SystemPowerState &&
1351 irp_sl->params.power.state.system_state > PowerSystemWorking) ||
1352 (irp_sl->params.power.type == DevicePowerState &&
1353 irp_sl->params.power.state.device_state > PowerDeviceD0))
1354 state = NdisDeviceStateD3;
1356 state = NdisDeviceStateD0;
1357 switch (irp_sl->minor_fn) {
1358 case IRP_MN_SET_POWER:
1359 if (state == NdisDeviceStateD0) {
1360 status = IoSyncForwardIrp(wnd->nmb->pdo, irp);
1361 if (status != STATUS_SUCCESS)
1363 ndis_status = mp_set_power_state(wnd, state);
1364 if (ndis_status != NDIS_STATUS_SUCCESS)
1365 WARNING("couldn't set power to %d: %08X",
1366 state, ndis_status);
1367 TRACE2("%s: device resumed", wnd->net_dev->name);
1368 irp->io_status.status = status = STATUS_SUCCESS;
1369 IoCompleteRequest(irp, IO_NO_INCREMENT);
1372 ndis_status = mp_set_power_state(wnd, state);
1373 /* TODO: handle error case */
1374 if (ndis_status != NDIS_STATUS_SUCCESS)
1375 WARNING("setting power to %d failed: %08X",
1376 state, ndis_status);
1377 status = IoAsyncForwardIrp(wnd->nmb->pdo, irp);
1380 case IRP_MN_QUERY_POWER:
1381 if (wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND) {
1382 ndis_status = mp_query(wnd, OID_PNP_QUERY_POWER,
1383 &state, sizeof(state));
1384 TRACE2("%d, %08X", state, ndis_status);
1385 /* this OID must always succeed */
1386 if (ndis_status != NDIS_STATUS_SUCCESS)
1387 TRACE1("query power returns %08X", ndis_status);
1388 irp->io_status.status = STATUS_SUCCESS;
1390 irp->io_status.status = STATUS_SUCCESS;
1391 status = IoPassIrpDown(wnd->nmb->pdo, irp);
1393 case IRP_MN_WAIT_WAKE:
1394 case IRP_MN_POWER_SEQUENCE:
1395 /* TODO: implement WAIT_WAKE */
1396 status = IoPassIrpDown(wnd->nmb->pdo, irp);
1399 status = IoPassIrpDown(wnd->nmb->pdo, irp);
1402 IOEXIT(return status);
1404 WIN_FUNC_DECL(NdisDispatchPower,2)
1406 wstdcall NTSTATUS NdisDispatchPnp(struct device_object *fdo, struct irp *irp)
1408 struct io_stack_location *irp_sl;
1409 struct ndis_device *wnd;
1410 struct device_object *pdo;
1413 IOTRACE("fdo: %p, irp: %p", fdo, irp);
1414 irp_sl = IoGetCurrentIrpStackLocation(irp);
1415 wnd = fdo->reserved;
1416 pdo = wnd->nmb->pdo;
1417 switch (irp_sl->minor_fn) {
1418 case IRP_MN_START_DEVICE:
1419 status = IoSyncForwardIrp(pdo, irp);
1420 if (status != STATUS_SUCCESS)
1422 if (ndis_start_device(wnd) == NDIS_STATUS_SUCCESS)
1423 status = STATUS_SUCCESS;
1425 status = STATUS_FAILURE;
1426 irp->io_status.status = status;
1427 IoCompleteRequest(irp, IO_NO_INCREMENT);
1429 case IRP_MN_QUERY_STOP_DEVICE:
1430 /* TODO: implement in NDIS */
1431 status = IoPassIrpDown(wnd->nmb->pdo, irp);
1433 case IRP_MN_STOP_DEVICE:
1435 irp->io_status.status = STATUS_SUCCESS;
1436 status = IoAsyncForwardIrp(pdo, irp);
1438 case IRP_MN_REMOVE_DEVICE:
1439 TRACE1("%s", wnd->net_dev->name);
1440 mp_pnp_event(wnd, NdisDevicePnPEventSurpriseRemoved, 0);
1441 if (ndis_remove_device(wnd)) {
1442 status = STATUS_FAILURE;
1445 /* wnd is already freed */
1446 status = IoAsyncForwardIrp(pdo, irp);
1447 IoDetachDevice(fdo);
1448 IoDeleteDevice(fdo);
1451 status = IoAsyncForwardIrp(pdo, irp);
1454 IOTRACE("status: %08X", status);
1455 IOEXIT(return status);
1457 WIN_FUNC_DECL(NdisDispatchPnp,2)
1459 static void set_task_offload(struct ndis_device *wnd, void *buf,
1462 struct ndis_task_offload_header *task_offload_header;
1463 struct ndis_task_offload *task_offload;
1464 struct ndis_task_tcp_ip_checksum *csum = NULL;
1465 struct ndis_task_tcp_large_send *tso = NULL;
1468 memset(buf, 0, buf_size);
1469 task_offload_header = buf;
1470 task_offload_header->version = NDIS_TASK_OFFLOAD_VERSION;
1471 task_offload_header->size = sizeof(*task_offload_header);
1472 task_offload_header->encap_format.flags.fixed_header_size = 1;
1473 task_offload_header->encap_format.header_size = sizeof(struct ethhdr);
1474 task_offload_header->encap_format.encap = IEEE_802_3_Encapsulation;
1475 status = mp_query(wnd, OID_TCP_TASK_OFFLOAD, buf, buf_size);
1476 TRACE1("%08X", status);
1477 if (status != NDIS_STATUS_SUCCESS)
1479 if (task_offload_header->offset_first_task == 0)
1481 task_offload = ((void *)task_offload_header +
1482 task_offload_header->offset_first_task);
1484 TRACE1("%d, %d", task_offload->version, task_offload->task);
1485 switch(task_offload->task) {
1486 case TcpIpChecksumNdisTask:
1487 csum = (void *)task_offload->task_buf;
1489 case TcpLargeSendNdisTask:
1490 tso = (void *)task_offload->task_buf;
1493 TRACE1("%d", task_offload->task);
1496 if (task_offload->offset_next_task == 0)
1498 task_offload = (void *)task_offload +
1499 task_offload->offset_next_task;
1502 TRACE1("%u, %u, %d, %d", tso->max_size, tso->min_seg_count,
1503 tso->tcp_opts, tso->ip_opts);
1506 TRACE1("%08x, %08x", csum->v4_tx.value, csum->v4_rx.value);
1507 task_offload_header->encap_format.flags.fixed_header_size = 1;
1508 task_offload_header->encap_format.header_size = sizeof(struct ethhdr);
1509 task_offload_header->offset_first_task = sizeof(*task_offload_header);
1510 task_offload = ((void *)task_offload_header +
1511 task_offload_header->offset_first_task);
1512 task_offload->offset_next_task = 0;
1513 task_offload->size = sizeof(*task_offload);
1514 task_offload->task = TcpIpChecksumNdisTask;
1515 memcpy(task_offload->task_buf, csum, sizeof(*csum));
1516 task_offload->task_buf_length = sizeof(*csum);
1517 status = mp_set(wnd, OID_TCP_TASK_OFFLOAD, task_offload_header,
1518 sizeof(*task_offload_header) +
1519 sizeof(*task_offload) + sizeof(*csum));
1520 TRACE1("%08X", status);
1521 if (status != NDIS_STATUS_SUCCESS)
1523 wnd->tx_csum = csum->v4_tx;
1524 if (csum->v4_tx.tcp_csum && csum->v4_tx.udp_csum) {
1525 if (csum->v4_tx.ip_csum) {
1526 wnd->net_dev->features |= NETIF_F_HW_CSUM;
1527 TRACE1("hw checksum enabled");
1529 wnd->net_dev->features |= NETIF_F_IP_CSUM;
1530 TRACE1("IP checksum enabled");
1532 if (wnd->sg_dma_size)
1533 wnd->net_dev->features |= NETIF_F_SG;
1535 wnd->rx_csum = csum->v4_rx;
1539 static void get_supported_oids(struct ndis_device *wnd)
1545 res = mp_query_info(wnd, OID_GEN_SUPPORTED_LIST, NULL, 0, NULL,
1547 if (!(res == NDIS_STATUS_BUFFER_TOO_SHORT ||
1548 res == NDIS_STATUS_INVALID_LENGTH))
1550 oids = kmalloc(needed, GFP_KERNEL);
1552 TRACE1("couldn't allocate memory");
1555 res = mp_query(wnd, OID_GEN_SUPPORTED_LIST, oids, needed);
1557 TRACE1("failed: %08X", res);
1561 for (i = 0, n = needed / sizeof(*oids); i < n; i++) {
1562 TRACE1("oid: %08X", oids[i]);
1563 /* if a wireless device didn't say so for
1564 * OID_GEN_PHYSICAL_MEDIUM (they should, but in case) */
1565 if (wnd->physical_medium != NdisPhysicalMediumWirelessLan &&
1566 oids[i] == OID_802_11_SSID)
1567 wnd->physical_medium = NdisPhysicalMediumWirelessLan;
1573 static void ndis_get_drvinfo(struct net_device *dev,
1574 struct ethtool_drvinfo *info)
1576 struct ndis_device *wnd = netdev_priv(dev);
1577 strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 2);
1578 strcat(info->driver, "+");
1579 strncat(info->driver, wnd->wd->driver->name,
1580 sizeof(info->driver) - strlen(DRIVER_NAME) - 1);
1581 strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 2);
1582 strcat(info->version, "+");
1583 strncat(info->version, wnd->wd->driver->version,
1584 sizeof(info->version) - strlen(DRIVER_VERSION) - 1);
1585 if (wrap_is_pci_bus(wnd->wd->dev_bus))
1586 strncpy(info->bus_info, pci_name(wnd->wd->pci.pdev),
1587 sizeof(info->bus_info) - 1);
1590 usb_make_path(wnd->wd->usb.udev, info->bus_info,
1591 sizeof(info->bus_info) - 1);
1596 static u32 ndis_get_link(struct net_device *dev)
1598 struct ndis_device *wnd = netdev_priv(dev);
1599 return netif_carrier_ok(wnd->net_dev);
1602 static void ndis_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1604 struct ndis_device *wnd = netdev_priv(dev);
1608 if (!(wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND))
1610 if (!wrap_is_pci_bus(wnd->wd->dev_bus))
1612 /* we always suspend to D3 */
1613 if (wnd->pnp_capa.wakeup.min_magic_packet_wakeup < NdisDeviceStateD3)
1615 wol->supported |= WAKE_MAGIC;
1616 if (wnd->ndis_wolopts & NDIS_PNP_WAKE_UP_MAGIC_PACKET)
1617 wol->wolopts |= WAKE_MAGIC;
1621 static int ndis_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1623 struct ndis_device *wnd = netdev_priv(dev);
1625 if (!(wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND))
1627 if (wnd->pnp_capa.wakeup.min_magic_packet_wakeup < NdisDeviceStateD3)
1628 EXIT2(return -EOPNOTSUPP);
1629 TRACE2("0x%x", wol->wolopts);
1630 if (wol->wolopts & WAKE_MAGIC) {
1631 wnd->ndis_wolopts |= NDIS_PNP_WAKE_UP_MAGIC_PACKET;
1632 if (wol->wolopts != WAKE_MAGIC)
1633 WARNING("ignored wake-on-lan options: 0x%x",
1634 wol->wolopts & ~WAKE_MAGIC);
1635 } else if (!wol->wolopts)
1636 wnd->ndis_wolopts = 0;
1639 TRACE2("0x%x", wnd->ndis_wolopts);
1643 static u32 ndis_get_tx_csum(struct net_device *dev)
1645 struct ndis_device *wnd = netdev_priv(dev);
1646 if (wnd->tx_csum.tcp_csum && wnd->tx_csum.udp_csum)
1652 static u32 ndis_get_rx_csum(struct net_device *dev)
1654 struct ndis_device *wnd = netdev_priv(dev);
1655 if (wnd->rx_csum.value)
1661 static int ndis_set_tx_csum(struct net_device *dev, u32 data)
1663 struct ndis_device *wnd = netdev_priv(dev);
1665 if (data && (wnd->tx_csum.value == 0))
1668 if (wnd->tx_csum.ip_csum)
1669 ethtool_op_set_tx_hw_csum(dev, data);
1671 ethtool_op_set_tx_csum(dev, data);
1675 static int ndis_set_rx_csum(struct net_device *dev, u32 data)
1677 struct ndis_device *wnd = netdev_priv(dev);
1679 if (data && (wnd->tx_csum.value == 0))
1682 /* TODO: enable/disable rx csum through NDIS */
1686 static u32 ndis_get_sg(struct net_device *dev)
1688 struct ndis_device *wnd = netdev_priv(dev);
1689 if (wnd->sg_dma_size)
1690 return ethtool_op_get_sg(dev);
1695 static int ndis_set_sg(struct net_device *dev, u32 data)
1697 struct ndis_device *wnd = netdev_priv(dev);
1698 if (wnd->sg_dma_size)
1699 return ethtool_op_set_sg(dev, data);
1704 static struct ethtool_ops ndis_ethtool_ops = {
1705 .get_drvinfo = ndis_get_drvinfo,
1706 .get_link = ndis_get_link,
1707 .get_wol = ndis_get_wol,
1708 .set_wol = ndis_set_wol,
1709 .get_tx_csum = ndis_get_tx_csum,
1710 .get_rx_csum = ndis_get_rx_csum,
1711 .set_tx_csum = ndis_set_tx_csum,
1712 .set_rx_csum = ndis_set_rx_csum,
1713 .get_sg = ndis_get_sg,
1714 .set_sg = ndis_set_sg,
1717 static int notifier_event(struct notifier_block *notifier, unsigned long event,
1720 struct net_device *net_dev = ptr;
1722 ENTER2("0x%lx", event);
1723 if (net_dev->ethtool_ops == &ndis_ethtool_ops
1724 && event == NETDEV_CHANGENAME) {
1725 struct ndis_device *wnd = netdev_priv(net_dev);
1726 /* called with rtnl lock held, so no need to lock */
1727 wrap_procfs_remove_ndis_device(wnd);
1728 printk(KERN_INFO "%s: changing interface name from '%s' to "
1729 "'%s'\n", DRIVER_NAME, wnd->netdev_name, net_dev->name);
1730 memcpy(wnd->netdev_name, net_dev->name,
1731 sizeof(wnd->netdev_name));
1732 wrap_procfs_add_ndis_device(wnd);
1737 static struct notifier_block netdev_notifier = {
1738 .notifier_call = notifier_event,
1741 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
1742 static const struct net_device_ops ndis_netdev_ops = {
1743 .ndo_open = ndis_net_dev_open,
1744 .ndo_stop = ndis_net_dev_close,
1745 .ndo_start_xmit = tx_skbuff,
1746 .ndo_change_mtu = ndis_change_mtu,
1747 .ndo_set_multicast_list = ndis_set_multicast_list,
1748 .ndo_set_mac_address = ndis_set_mac_address,
1749 .ndo_get_stats = ndis_get_stats,
1750 #ifdef CONFIG_NET_POLL_CONTROLLER
1751 .ndo_poll_controller = ndis_poll_controller,
1756 static NDIS_STATUS ndis_start_device(struct ndis_device *wnd)
1758 struct wrap_device *wd;
1759 struct net_device *net_dev;
1762 const int buf_len = 256;
1764 struct transport_header_offset *tx_header_offset;
1767 ENTER2("%d", in_atomic());
1768 status = mp_init(wnd);
1769 if (status == NDIS_STATUS_NOT_RECOGNIZED)
1770 EXIT1(return NDIS_STATUS_SUCCESS);
1771 if (status != NDIS_STATUS_SUCCESS)
1772 EXIT1(return status);
1774 net_dev = wnd->net_dev;
1776 get_supported_oids(wnd);
1777 memset(mac, 0, sizeof(mac));
1778 status = mp_query(wnd, OID_802_3_CURRENT_ADDRESS, mac, sizeof(mac));
1779 if (memcmp(mac, "\x00\x00\x00\x00\x00\x00", sizeof(mac)) == 0) {
1780 status = mp_query(wnd, OID_802_3_PERMANENT_ADDRESS, mac,
1782 if (status != NDIS_STATUS_SUCCESS) {
1783 ERROR("couldn't get mac address: %08X", status);
1787 TRACE1("mac:" MACSTRSEP, MAC2STR(mac));
1788 memcpy(net_dev->dev_addr, mac, ETH_ALEN);
1790 strncpy(net_dev->name, if_name, IFNAMSIZ - 1);
1791 net_dev->name[IFNAMSIZ - 1] = 0;
1793 wnd->packet_filter = NDIS_PACKET_TYPE_DIRECTED |
1794 NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_MULTICAST;
1795 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
1796 net_dev->netdev_ops = &ndis_netdev_ops;
1798 net_dev->open = ndis_net_dev_open;
1799 net_dev->hard_start_xmit = tx_skbuff;
1800 net_dev->stop = ndis_net_dev_close;
1801 net_dev->get_stats = ndis_get_stats;
1802 net_dev->change_mtu = ndis_change_mtu;
1803 net_dev->set_multicast_list = ndis_set_multicast_list;
1804 net_dev->set_mac_address = ndis_set_mac_address;
1805 #ifdef CONFIG_NET_POLL_CONTROLLER
1806 net_dev->poll_controller = ndis_poll_controller;
1809 if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) {
1810 net_dev->wireless_handlers = &ndis_handler_def;
1812 net_dev->ethtool_ops = &ndis_ethtool_ops;
1813 if (wnd->mp_interrupt)
1814 net_dev->irq = wnd->mp_interrupt->irq;
1815 net_dev->mem_start = wnd->mem_start;
1816 net_dev->mem_end = wnd->mem_end;
1817 status = mp_query_int(wnd, OID_802_3_MAXIMUM_LIST_SIZE,
1818 &wnd->multicast_size);
1819 if (status != NDIS_STATUS_SUCCESS || wnd->multicast_size < 0)
1820 wnd->multicast_size = 0;
1821 if (wnd->multicast_size > 0)
1822 net_dev->flags |= IFF_MULTICAST;
1824 net_dev->flags &= ~IFF_MULTICAST;
1826 buf = kmalloc(buf_len, GFP_KERNEL);
1828 WARNING("couldn't allocate memory");
1832 set_task_offload(wnd, buf, buf_len);
1834 net_dev->features |= NETIF_F_LLTX;
1837 if (register_netdev(net_dev)) {
1838 ERROR("cannot register net device %s", net_dev->name);
1841 memcpy(wnd->netdev_name, net_dev->name, sizeof(wnd->netdev_name));
1842 memset(buf, 0, buf_len);
1843 status = mp_query(wnd, OID_GEN_VENDOR_DESCRIPTION, buf, buf_len);
1844 if (status != NDIS_STATUS_SUCCESS) {
1845 WARNING("couldn't get vendor information: 0x%x", status);
1848 wnd->drv_ndis_version = n = 0;
1849 mp_query_int(wnd, OID_GEN_DRIVER_VERSION, &wnd->drv_ndis_version);
1850 mp_query_int(wnd, OID_GEN_VENDOR_DRIVER_VERSION, &n);
1852 printk(KERN_INFO "%s: ethernet device " MACSTRSEP " using %sNDIS "
1853 "driver: %s, version: 0x%x, NDIS version: 0x%x, vendor: '%s', "
1854 "%s\n", net_dev->name, MAC2STR(net_dev->dev_addr),
1855 deserialized_driver(wnd) ? "" : "serialized ",
1856 wnd->wd->driver->name, n, wnd->drv_ndis_version, buf,
1857 wnd->wd->conf_file_name);
1859 if (deserialized_driver(wnd)) {
1860 /* deserialized drivers don't have a limit, but we
1861 * keep max at TX_RING_SIZE */
1862 wnd->max_tx_packets = TX_RING_SIZE;
1864 status = mp_query_int(wnd, OID_GEN_MAXIMUM_SEND_PACKETS,
1865 &wnd->max_tx_packets);
1866 if (status != NDIS_STATUS_SUCCESS)
1867 wnd->max_tx_packets = 1;
1868 if (wnd->max_tx_packets > TX_RING_SIZE)
1869 wnd->max_tx_packets = TX_RING_SIZE;
1871 TRACE2("maximum send packets: %d", wnd->max_tx_packets);
1872 NdisAllocatePacketPoolEx(&status, &wnd->tx_packet_pool,
1873 wnd->max_tx_packets, 0,
1874 PROTOCOL_RESERVED_SIZE_IN_PACKET);
1875 if (status != NDIS_STATUS_SUCCESS) {
1876 ERROR("couldn't allocate packet pool");
1877 goto packet_pool_err;
1879 NdisAllocateBufferPool(&status, &wnd->tx_buffer_pool,
1880 wnd->max_tx_packets + 4);
1881 if (status != NDIS_STATUS_SUCCESS) {
1882 ERROR("couldn't allocate buffer pool");
1883 goto buffer_pool_err;
1885 TRACE1("pool: %p", wnd->tx_buffer_pool);
1887 if (mp_query_int(wnd, OID_GEN_MAXIMUM_TOTAL_SIZE, &n) ==
1888 NDIS_STATUS_SUCCESS && n > ETH_HLEN)
1889 ndis_change_mtu(wnd->net_dev, n - ETH_HLEN);
1891 if (mp_query_int(wnd, OID_GEN_MAC_OPTIONS, &n) == NDIS_STATUS_SUCCESS)
1892 TRACE2("mac options supported: 0x%x", n);
1894 tx_header_offset = (typeof(tx_header_offset))buf;
1895 tx_header_offset->protocol_type = NDIS_PROTOCOL_ID_TCP_IP;
1896 tx_header_offset->header_offset = sizeof(ETH_HLEN);
1897 status = mp_set(wnd, OID_GEN_TRANSPORT_HEADER_OFFSET,
1898 tx_header_offset, sizeof(*tx_header_offset));
1899 TRACE2("%08X", status);
1901 status = mp_query_int(wnd, OID_GEN_PHYSICAL_MEDIUM,
1902 &wnd->physical_medium);
1903 if (status != NDIS_STATUS_SUCCESS)
1904 wnd->physical_medium = NdisPhysicalMediumUnspecified;
1906 if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) {
1907 mp_set_int(wnd, OID_802_11_POWER_MODE, NDIS_POWER_OFF);
1908 get_encryption_capa(wnd, buf, buf_len);
1909 TRACE1("capbilities = %ld", wnd->capa.encr);
1910 printk(KERN_INFO "%s: encryption modes supported: "
1911 "%s%s%s%s%s%s%s\n", net_dev->name,
1912 test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr) ?
1915 test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr) ?
1916 "; TKIP with WPA" : "",
1917 test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ?
1919 test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ?
1922 test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr) ?
1923 "; AES/CCMP with WPA" : "",
1924 test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ?
1926 test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ?
1929 set_default_iw_params(wnd);
1931 status = mp_query_int(wnd, OID_GEN_MEDIA_CONNECT_STATUS, (int *)buf);
1932 if (status == NDIS_STATUS_SUCCESS)
1933 set_media_state(wnd, *((int *)buf));
1935 wrap_procfs_add_ndis_device(wnd);
1937 add_iw_stats_timer(wnd);
1938 EXIT1(return NDIS_STATUS_SUCCESS);
1941 wnd->tx_buffer_pool = NULL;
1942 if (wnd->tx_packet_pool) {
1943 NdisFreePacketPool(wnd->tx_packet_pool);
1944 wnd->tx_packet_pool = NULL;
1950 ndis_remove_device(wnd);
1951 EXIT1(return NDIS_STATUS_FAILURE);
1954 static int ndis_remove_device(struct ndis_device *wnd)
1958 /* prevent setting essid during disassociation */
1959 memset(&wnd->essid, 0, sizeof(wnd->essid));
1961 if (wnd->max_tx_packets)
1962 unregister_netdev(wnd->net_dev);
1963 netif_carrier_off(wnd->net_dev);
1964 /* if device is suspended, but resume failed, tx_ring_mutex
1965 * may already be locked */
1966 if (down_trylock(&wnd->tx_ring_mutex))
1967 WARNING("couldn't obtain tx_ring_mutex");
1968 spin_lock_bh(&wnd->tx_ring_lock);
1969 tx_pending = wnd->tx_ring_end - wnd->tx_ring_start;
1971 tx_pending += TX_RING_SIZE;
1972 else if (tx_pending == 0 && wnd->is_tx_ring_full)
1973 tx_pending = TX_RING_SIZE - 1;
1974 wnd->is_tx_ring_full = 0;
1975 /* throw away pending packets */
1976 while (tx_pending-- > 0) {
1977 struct ndis_packet *packet;
1979 packet = wnd->tx_ring[wnd->tx_ring_start];
1980 free_tx_packet(wnd, packet, NDIS_STATUS_CLOSING);
1981 wnd->tx_ring_start = (wnd->tx_ring_start + 1) % TX_RING_SIZE;
1983 spin_unlock_bh(&wnd->tx_ring_lock);
1984 up(&wnd->tx_ring_mutex);
1985 wrap_procfs_remove_ndis_device(wnd);
1987 ndis_exit_device(wnd);
1989 if (wnd->tx_packet_pool) {
1990 NdisFreePacketPool(wnd->tx_packet_pool);
1991 wnd->tx_packet_pool = NULL;
1993 if (wnd->tx_buffer_pool) {
1994 NdisFreeBufferPool(wnd->tx_buffer_pool);
1995 wnd->tx_buffer_pool = NULL;
1999 printk(KERN_INFO "%s: device %s removed\n", DRIVER_NAME,
2000 wnd->net_dev->name);
2002 free_netdev(wnd->net_dev);
2006 static wstdcall NTSTATUS NdisAddDevice(struct driver_object *drv_obj,
2007 struct device_object *pdo)
2009 struct device_object *fdo;
2010 struct ndis_mp_block *nmb;
2012 struct ndis_device *wnd;
2013 struct net_device *net_dev;
2014 struct wrap_device *wd;
2017 ENTER2("%p, %p", drv_obj, pdo);
2018 if (strlen(if_name) >= IFNAMSIZ) {
2019 ERROR("interface name '%s' is too long", if_name);
2020 return STATUS_INVALID_PARAMETER;
2022 net_dev = alloc_etherdev(sizeof(*wnd));
2024 ERROR("couldn't allocate device");
2025 return STATUS_RESOURCES;
2028 if (wrap_is_pci_bus(wd->dev_bus))
2029 SET_NETDEV_DEV(net_dev, &wd->pci.pdev->dev);
2030 if (wrap_is_usb_bus(wd->dev_bus))
2031 SET_NETDEV_DEV(net_dev, &wd->usb.intf->dev);
2032 status = IoCreateDevice(drv_obj, 0, NULL, FILE_DEVICE_UNKNOWN, 0,
2034 if (status != STATUS_SUCCESS) {
2035 free_netdev(net_dev);
2036 EXIT2(return status);
2038 wnd = netdev_priv(net_dev);
2039 TRACE1("wnd: %p", wnd);
2041 nmb = kmalloc(sizeof(*nmb), GFP_KERNEL);
2043 WARNING("couldn't allocate memory");
2044 IoDeleteDevice(fdo);
2045 free_netdev(net_dev);
2046 return STATUS_RESOURCES;
2048 #if defined(DEBUG) && DEBUG >= 6
2049 /* poison nmb so if a driver accesses uninitialized pointers, we
2050 * know what it is */
2051 for (i = 0; i < sizeof(*nmb) / sizeof(unsigned long); i++)
2052 ((unsigned long *)nmb)[i] = i + 0x8a3fc1;
2060 wnd->net_dev = net_dev;
2061 fdo->reserved = wnd;
2063 if (ndis_init_device(wnd)) {
2064 IoDeleteDevice(fdo);
2066 free_netdev(net_dev);
2067 EXIT1(return STATUS_RESOURCES);
2069 nmb->next_device = IoAttachDeviceToDeviceStack(fdo, pdo);
2070 spin_lock_init(&wnd->tx_ring_lock);
2071 sema_init(&wnd->tx_ring_mutex, 1);
2072 sema_init(&wnd->ndis_req_mutex, 1);
2073 wnd->ndis_req_done = 0;
2074 initialize_work(&wnd->tx_work, tx_worker, wnd);
2075 wnd->tx_ring_start = 0;
2076 wnd->tx_ring_end = 0;
2077 wnd->is_tx_ring_full = 0;
2080 wnd->attributes = 0;
2081 wnd->dma_map_count = 0;
2082 wnd->dma_map_addr = NULL;
2084 init_timer(&wnd->hangcheck_timer);
2085 wnd->scan_timestamp = 0;
2086 init_timer(&wnd->iw_stats_timer);
2087 wnd->iw_stats_interval = 10 * HZ;
2088 wnd->ndis_pending_work = 0;
2089 memset(&wnd->essid, 0, sizeof(wnd->essid));
2090 memset(&wnd->encr_info, 0, sizeof(wnd->encr_info));
2091 wnd->infrastructure_mode = Ndis802_11Infrastructure;
2092 initialize_work(&wnd->ndis_work, ndis_worker, wnd);
2093 wnd->iw_stats_enabled = TRUE;
2095 TRACE1("nmb: %p, pdo: %p, fdo: %p, attached: %p, next: %p",
2096 nmb, pdo, fdo, fdo->attached, nmb->next_device);
2098 /* dispatch routines are called as Windows functions */
2099 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
2100 drv_obj->major_func[i] = WIN_FUNC_PTR(IoPassIrpDown,2);
2102 drv_obj->major_func[IRP_MJ_PNP] = WIN_FUNC_PTR(NdisDispatchPnp,2);
2103 drv_obj->major_func[IRP_MJ_POWER] = WIN_FUNC_PTR(NdisDispatchPower,2);
2104 drv_obj->major_func[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
2105 WIN_FUNC_PTR(NdisDispatchDeviceControl,2);
2106 // drv_obj->major_func[IRP_MJ_DEVICE_CONTROL] =
2107 // WIN_FUNC_PTR(NdisDispatchDeviceControl,2);
2108 EXIT2(return STATUS_SUCCESS);
2111 int init_ndis_driver(struct driver_object *drv_obj)
2113 ENTER1("%p", drv_obj);
2114 drv_obj->drv_ext->add_device = NdisAddDevice;
2118 int wrapndis_init(void)
2120 wrapndis_wq = create_singlethread_workqueue("wrapndis_wq");
2122 EXIT1(return -ENOMEM);
2123 wrapndis_worker_thread = wrap_worker_init(wrapndis_wq);
2124 TRACE1("%p", wrapndis_worker_thread);
2125 register_netdevice_notifier(&netdev_notifier);
2129 void wrapndis_exit(void)
2131 unregister_netdevice_notifier(&netdev_notifier);
2133 destroy_workqueue(wrapndis_wq);
2134 TRACE1("%p", wrapndis_worker_thread);
2135 if (wrapndis_worker_thread)
2136 ObDereferenceObject(wrapndis_worker_thread);