aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/if_ndis
Commit message (Collapse)AuthorAgeFilesLines
...
* Avoid trying to queue up an interrupt handler DPC if the driverBill Paul2005-05-081-1/+1
| | | | | | | hasn't called NdisMRegisterInterrupt() yet. Notes: svn path=/head/; revision=146000
* Minor correction to the logic for selecting the proper device index.Bill Paul2005-05-081-1/+1
| | | | Notes: svn path=/head/; revision=145995
* Avoid sleeping with mutex held in kern_ndis.c.Bill Paul2005-05-051-2/+2
| | | | | | | | | | | | | | | | | | Remove unused fields from ndis_miniport_block. Fix a bug in KeFlushQueuedDpcs() (we weren't calculating the kq pointer correctly). In if_ndis.c, clear the IFF_RUNNING flag before calling ndis_halt_nic(). Add some guards in kern_ndis.c to avoid letting anyone invoke ndis_get_info() or ndis_set_info() if the NIC isn't fully initialized. Apparently, mdnsd will sometimes try to invoke the ndis_ioctl() routine at exactly the wrong moment (to futz with its multicast filters) when the interface comes up, and can trigger a crash unless we guard against it. Notes: svn path=/head/; revision=145898
* This commit makes a bunch of changes, some big, some not so big.Bill Paul2005-05-052-17/+54
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | - Remove the old task threads from kern_ndis.c and reimplement them in subr_ntoskrnl.c, in order to more properly emulate the Windows DPC API. Each CPU gets its own DPC queue/thread, and each queue can have low, medium and high importance DPCs. New APIs implemented: KeSetTargetProcessorDpc(), KeSetImportanceDpc() and KeFlushQueuedDpcs(). (This is the biggest change.) - Fix a bug in NdisMInitializeTimer(): the k_dpc pointer in the nmt_timer embedded in the ndis_miniport_timer struct must be set to point to the DPC, also embedded in the struct. Failing to do this breaks dequeueing of DPCs submitted via timers, and in turn breaks cancelling timers. - Fix a bug in KeCancelTimer(): if the timer is interted in the timer queue (i.e. the timeout callback is still pending), we have to both untimeout() the timer _and_ call KeRemoveQueueDpc() to nuke the DPC that might be pending. Failing to do this breaks cancellation of periodic timers, which always appear to be inserted in the timer queue. - Make use of the nmt_nexttimer field in ndis_miniport_timer: keep a queue of pending timers and cancel them all in ndis_halt_nic(), prior to calling MiniportHalt(). Also call KeFlushQueuedDpcs() to make sure any DPCs queued by the timers have expired. - Modify NdisMAllocateSharedMemory() and NdisMFreeSharedMemory() to keep track of both the virtual and physical addresses of the shared memory buffers that get handed out. The AirGo MIMO driver appears to have a bug in it: for one of the segments is allocates, it returns the wrong virtual address. This would confuse NdisMFreeSharedMemory() and cause a crash. Why it doesn't crash Windows too I have no idea (from reading the documentation for NdisMFreeSharedMemory(), it appears to be a violation of the API). - Implement strstr(), strchr() and MmIsAddressValid(). - Implement IoAllocateWorkItem(), IoFreeWorkItem(), IoQueueWorkItem() and ExQueueWorkItem(). (This is the second biggest change.) - Make NdisScheduleWorkItem() call ExQueueWorkItem(). (Note that the ExQueueWorkItem() API is deprecated by Microsoft, but NDIS still uses it, since NdisScheduleWorkItem() is incompatible with the IoXXXWorkItem() API.) - Change if_ndis.c to use the NdisScheduleWorkItem() interface for scheduling tasks. With all these changes and fixes, the AirGo MIMO driver for the Belkin F5D8010 Pre-N card now works. Special thanks to Paul Robinson (paul dawt robinson at pwermedia dawt net) for the loan of a card for testing. Notes: svn path=/head/; revision=145895
* Throw the switch on the new driver generation/loading mechanism. FromBill Paul2005-04-245-149/+92
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | here on in, if_ndis.ko will be pre-built as a module, and can be built into a static kernel (though it's not part of GENERIC). Drivers are created using the new ndisgen(8) script, which uses ndiscvt(8) under the covers, along with a few other tools. The result is a driver module that can be kldloaded into the kernel. A driver with foo.inf and foo.sys files will be converted into foo_sys.ko (and foo_sys.o, for those who want/need to make static kernels). This module contains all of the necessary info from the .INF file and the driver binary image, converted into an ELF module. You can kldload this module (or add it to /boot/loader.conf) to have it loaded automatically. Any required firmware files can be bundled into the module as well (or converted/loaded separately). Also, add a workaround for a problem in NdisMSleep(). During system bootstrap (cold == 1), msleep() always returns 0 without actually sleeping. The Intel 2200BG driver uses NdisMSleep() to wait for the NIC's firmware to come to life, and fails to load if NdisMSleep() doesn't actually delay. As a workaround, if msleep() (and hence ndis_thsuspend()) returns 0, use a hard DELAY() to sleep instead). This is not really the right thing to do, but we can't really do much else. At the very least, this makes the Intel driver happy. There are probably other drivers that fail in this way during bootstrap. Unfortunately, the only workaround for those is to avoid pre-loading them and kldload them once the system is running instead. Notes: svn path=/head/; revision=145485
* Small cleanup of the WPA code additions. The SIOCG80211 and SIOCS80211Bill Paul2005-04-201-4/+5
| | | | | | | | | | | ioctls are now handled explicitly, but we can't really do anything with them unless the NIC is up (trying to get/set a parameter when the NDIS driver isn't running always yields an error). If something invokes either of these ioctls and the NIC isn't initialized, punt to the default ieee80211_ioctl() routine. Notes: svn path=/head/; revision=145310
* Add preliminary support for WPA-PSK using wpa_supplicant and theBill Paul2005-04-191-2/+319
| | | | | | | | | net80211 code, graciously contributed by Arvind Srinivasan. Submitted by: Arvind Srinivasan arvind at celar daht us Notes: svn path=/head/; revision=145283
* Create new i386 windows/bsd thunking layer, similar to the amd64 thunkingBill Paul2005-04-111-17/+26
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | layer, but with a twist. The twist has to do with the fact that Microsoft supports structured exception handling in kernel mode. On the i386 arch, exception handling is implemented by hanging an exception registration list off the Thread Environment Block (TEB), and the TEB is accessed via the %fs register. The problem is, we use %fs as a pointer to the pcpu stucture, which means any driver that tries to write through %fs:0 will overwrite the curthread pointer and make a serious mess of things. To get around this, Project Evil now creates a special entry in the GDT on each processor. When we call into Windows code, a context switch routine will fix up %fs so it points to our new descriptor, which in turn points to a fake TEB. When the Windows code returns, or calls out to an external routine, we swap %fs back again. Currently, Project Evil makes use of GDT slot 7, which is all 0s by default. I fully expect someone to jump up and say I can't do that, but I couldn't find any code that makes use of this entry anywhere. Sadly, this was the only method I could come up with that worked on both UP and SMP. (Modifying the LDT works on UP, but becomes incredibly complicated on SMP.) If necessary, the context switching stuff can be yanked out while preserving the convention calling wrappers. (Fortunately, it looks like Microsoft uses some special epilog/prolog code on amd64 to implement exception handling, so the same nastiness won't be necessary on that arch.) The advantages are: - Any driver that uses %fs as though it were a TEB pointer won't clobber pcpu. - All the __stdcall/__fastcall/__regparm stuff that's specific to gcc goes away. Also, while I'm here, switch NdisGetSystemUpTime() back to using nanouptime() again. It turns out nanouptime() is way more accurate than just using ticks(). On slower machines, the Atheros drivers I tested seem to take a long time to associate due to the loss in accuracy. Notes: svn path=/head/; revision=144888
* Remove the last vestiges of the "wait for link down event" hack.Bill Paul2005-03-281-4/+0
| | | | Notes: svn path=/head/; revision=144255
* Argh. PCI resource list became an STAILQ instead of an SLIST. Try toBill Paul2005-03-271-0/+4
| | | | | | | | deal with this while maintaining backards source compatibility with stable. Notes: svn path=/head/; revision=144176
* Finally bring an end to the great "make the Atheros NDIS driverBill Paul2005-03-271-67/+59
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | work on SMP" saga. After several weeks and much gnashing of teeth, I have finally tracked down all the problems, despite their best efforts to confound and annoy me. Problem nunmber one: the Atheros windows driver is _NOT_ a de-serialized miniport! It used to be that NDIS drivers relied on the NDIS library itself for all their locking and serialization needs. Transmit packet queues were all handled internally by NDIS, and all calls to MiniportXXX() routines were guaranteed to be appropriately serialized. This proved to be a performance problem however, and Microsoft introduced de-serialized miniports with the NDIS 5.x spec. Microsoft still supports serialized miniports, but recommends that all new drivers written for Windows XP and later be deserialized. Apparently Atheros wasn't listening when they said this. This means (among other things) that we have to serialize calls to MiniportSendPackets(). We also have to serialize calls to MiniportTimer() that are triggered via the NdisMInitializeTimer() routine. It finally dawned on me why NdisMInitializeTimer() takes a special NDIS_MINIPORT_TIMER structure and a pointer to the miniport block: the timer callback must be serialized, and it's only by saving the miniport block handle that we can get access to the serialization lock during the timer callback. Problem number two: haunted hardware. The thing that was _really_ driving me absolutely bonkers for the longest time is that, for some reason I couldn't understand, my test machine would occasionally freeze or more frustratingly, reset completely. That's reset and in *pow!* back to the BIOS startup. No panic, no crashdump, just a reset. This appeared to happen most often when MiniportReset() was called. (As to why MiniportReset() was being called, see problem three below.) I thought maybe I had created some sort of horrible deadlock condition in the process of adding the serialization, but after three weeks, at least 6 different locking implementations and heroic efforts to debug the spinlock code, the machine still kept resetting. Finally, I started single stepping through the MiniportReset() routine in the driver using the kernel debugger, and this ultimately led me to the source of the problem. One of the last things the Atheros MiniportReset() routine does is call NdisReadPciSlotInformation() several times to inspect a portion of the device's PCI config space. It reads the same chunk of config space repeatedly, in rapid succession. Presumeably, it's polling the hardware for some sort of event. The reset occurs partway through this process. I discovered that when I single-stepped through this portion of the routine, the reset didn't occur. So I inserted a 1 microsecond delay into the read loop in NdisReadPciSlotInformation(). Suddenly, the reset was gone!! I'm still very puzzled by the whole thing. What I suspect is happening is that reading the PCI config space so quickly is causing a severe PCI bus error. My test system is a Sun w2100z dual Opteron system, and the NIC is a miniPCI card mounted in a miniPCI-to-PCI carrier card, plugged into a 100Mhz PCI slot. It's possible that this combination of hardware causes a bus protocol violation in this scenario which leads to a fatal machine check. This is pure speculation though. Really all I know for sure is that inserting the delay makes the problem go away. (To quote Homer Simpson: "I don't know how it works, but fire makes it good!") Problem number three: NdisAllocatePacket() needs to make sure to initialize the npp_validcounts field in the 'private' section of the NDIS_PACKET structure. The reason if_ndis was calling the MiniportReset() routine in the first place is that packet transmits were sometimes hanging. When sending a packet, an NDIS driver will call NdisQueryPacket() to learn how many physical buffers the packet resides in. NdisQueryPacket() is actually a macro, which traverses the NDIS_BUFFER list attached to the NDIS_PACKET and stashes some of the results in the 'private' section of the NDIS_PACKET. It also sets the npp_validcounts field to TRUE To indicate that the results are now valid. The problem is, now that if_ndis creates a pool of transmit packets via NdisAllocatePacketPool(), it's important that each time a new packet is allocated via NdisAllocatePacket() that validcounts be initialized to FALSE. If it isn't, and a previously transmitted NDIS_PACKET is pulled out of the pool, it may contain stale data from a previous transmission which won't get updated by NdisQueryPacket(). This would cause the driver to miscompute the number of fragments for a given packet, and botch the transmission. Fixing these three problems seems to make the Atheros driver happy on SMP, which hopefully means other serialized miniports will be happy too. And there was much rejoicing. Other stuff fixed along the way: - Modified ndis_thsuspend() to take a mutex as an argument. This allows KeWaitForSingleObject() and KeWaitForMultipleObjects() to avoid any possible race conditions with other routines that use the dispatcher lock. - Fixed KeCancelTimer() so that it returns the correct value for 'pending' according to the Microsoft documentation - Modfied NdisGetSystemUpTime() to use ticks and hz rather than calling nanouptime(). Also added comment that this routine wraps after 49.7 days. - Added macros for KeAcquireSpinLock()/KeReleaseSpinLock() to hide all the MSCALL() goop. - For x86, KeAcquireSpinLockRaiseToDpc() needs to be a separate function. This is because it's supposed to be _stdcall on the x86 arch, whereas KeAcquireSpinLock() is supposed to be _fastcall. On amd64, all routines use the same calling convention so we can just map KeAcquireSpinLockRaiseToDpc() directly to KfAcquireSpinLock() and it will work. (The _fastcall attribute is a no-op on amd64.) - Implement and use IoInitializeDpcRequest() and IoRequestDpc() (they're just macros) and use them for interrupt handling. This allows us to move the ndis_intrtask() routine from if_ndis.c to kern_ndis.c. - Fix the MmInitializeMdl() macro so that is uses sizeof(vm_offset_t) when computing mdl_size instead of uint32_t, so that it matches the MmSizeOfMdl() routine. - Change a could of M_WAITOKs to M_NOWAITs in the unicode routines in subr_ndis.c. - Use the dispatcher lock a little more consistently in subr_ntoskrnl.c. - Get rid of the "wait for link event" hack in ndis_init(). Now that I fixed NdisReadPciSlotInformation(), it seems I don't need it anymore. This should fix the witness panic a couple of people have reported. - Use MSCALL1() when calling the MiniportHangCheck() function in ndis_ticktask(). I accidentally missed this one when adding the wrapping for amd64. Notes: svn path=/head/; revision=144174
* s/SLIST/STAILQ/Maxim Konovalov2005-03-191-1/+1
| | | | | | | Spotted by: clive Notes: svn path=/head/; revision=143848
* When you call MiniportInitialize() for an 802.11 driver, it willBill Paul2005-03-071-4/+38
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | at some point result in a status event being triggered (it should be a link down event: the Microsoft driver design guide says you should generate one when the NIC is initialized). Some drivers generate the event during MiniportInitialize(), such that by the time MiniportInitialize() completes, the NIC is ready to go. But some drivers, in particular the ones for Atheros wireless NICs, don't generate the event until after a device interrupt occurs at some point after MiniportInitialize() has completed. The gotcha is that you have to wait until the link status event occurs one way or the other before you try to fiddle with any settings (ssid, channel, etc...). For the drivers that set the event sycnhronously this isn't a problem, but for the others we have to pause after calling ndis_init_nic() and wait for the event to arrive before continuing. Failing to wait can cause big trouble: on my SMP system, calling ndis_setstate_80211() after ndis_init_nic() completes, but _before_ the link event arrives, will lock up or reset the system. What we do now is check to see if a link event arrived while ndis_init_nic() was running, and if it didn't we msleep() until it does. Along the way, I discovered a few other problems: - Defered procedure calls run at PASSIVE_LEVEL, not DISPATCH_LEVEL. ntoskrnl_run_dpc() has been fixed accordingly. (I read the documentation wrong.) - Similarly, the NDIS interrupt handler, which is essentially a DPC, also doesn't need to run at DISPATCH_LEVEL. ndis_intrtask() has been fixed accordingly. - MiniportQueryInformation() and MiniportSetInformation() run at DISPATCH_LEVEL, and each request must complete before another can be submitted. ndis_get_info() and ndis_set_info() have been fixed accordingly. - Turned the sleep lock that guards the NDIS thread job list into a spin lock. We never do anything with this lock held except manage the job list (no other locks are held), so it's safe to do this, and it's possible that ndis_sched() and ndis_unsched() can be called from DISPATCH_LEVEL, so using a sleep lock here is semantically incorrect. Also updated subr_witness.c to add the lock to the order list. Notes: svn path=/head/; revision=143204
* Use 0 instead if NULL for vm_offset_t argument to windrv_lookup() toBill Paul2005-02-284-10/+10
| | | | | | | silence compiler warnings. Notes: svn path=/head/; revision=142804
* Correct e-mail address in copyright.Bill Paul2005-02-251-1/+1
| | | | Notes: svn path=/head/; revision=142415
* Apparently, the probe routine in if_ndis_usb.c can be called twiceBill Paul2005-02-242-9/+9
| | | | | | | | | | | | | for a given device in some circumstances, so move the PDO creation to the attach routine so we don't end up creating two PDOs. Also, when we skip the call to ndis_convert_res() in if_ndis.c:ndis_attach(), initialize sc->ndis_block->nmb_rlist to NULL. We don't explicitly zero the miniport block, so this will make sure ndis_unload_driver() does the right thing. Notes: svn path=/head/; revision=142408
* - Correct one aspect of the driver_object/device_object/IRP framework:Bill Paul2005-02-244-18/+211
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | when we create a PDO, the driver_object associated with it is that of the parent driver, not the driver we're trying to attach. For example, if we attach a PCI device, the PDO we pass to the NdisAddDevice() function should contain a pointer to fake_pci_driver, not to the NDIS driver itself. For PCI or PCMCIA devices this doesn't matter because the child never needs to talk to the parent bus driver, but for USB, the child needs to be able to send IRPs to the parent USB bus driver, and for that to work the parent USB bus driver has to be hung off the PDO. This involves modifying windrv_lookup() so that we can search for bus drivers by name, if necessary. Our fake bus drivers attach themselves as "PCI Bus," "PCCARD Bus" and "USB Bus," so we can search for them using those names. The individual attachment stubs now create and attach PDOs to the parent bus drivers instead of hanging them off the NDIS driver's object, and in if_ndis.c, we now search for the correct driver object depending on the bus type, and use that to find the correct PDO. With this fix, I can get my sample USB ethernet driver to deliver an IRP to my fake parent USB bus driver's dispatch routines. - Add stub modules for USB support: subr_usbd.c, usbd_var.h and if_ndis_usb.c. The subr_usbd.c module is hooked up the build but currently doesn't do very much. It provides the stub USB parent driver object and a dispatch routine for IRM_MJ_INTERNAL_DEVICE_CONTROL. The only exported function at the moment is USBD_GetUSBDIVersion(). The if_ndis_usb.c stub compiles, but is not hooked up to the build yet. I'm putting these here so I can keep them under source code control as I flesh them out. Notes: svn path=/head/; revision=142399
* Add support for Windows/x86-64 binaries to Project Evil.Bill Paul2005-02-162-17/+52
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Ville-Pertti Keinonen (will at exomi dot comohmygodnospampleasekthx) deserves a big thanks for submitting initial patches to make it work. I have mangled his contributions appropriately. The main gotcha with Windows/x86-64 is that Microsoft uses a different calling convention than everyone else. The standard ABI requires using 6 registers for argument passing, with other arguments on the stack. Microsoft uses only 4 registers, and requires the caller to leave room on the stack for the register arguments incase the callee needs to spill them. Unlike x86, where Microsoft uses a mix of _cdecl, _stdcall and _fastcall, all routines on Windows/x86-64 uses the same convention. This unfortunately means that all the functions we export to the driver require an intermediate translation wrapper. Similarly, we have to wrap all calls back into the driver binary itself. The original patches provided macros to wrap every single routine at compile time, providing a secondary jump table with a customized wrapper for each exported routine. I decided to use a different approach: the call wrapper for each function is created from a template at runtime, and the routine to jump to is patched into the wrapper as it is created. The subr_pe module has been modified to patch in the wrapped function instead of the original. (On x86, the wrapping routine is a no-op.) There are some minor API differences that had to be accounted for: - KeAcquireSpinLock() is a real function on amd64, not a macro wrapper around KfAcquireSpinLock() - NdisFreeBuffer() is actually IoFreeMdl(). I had to change the whole NDIS_BUFFER API a bit to accomodate this. Bugs fixed along the way: - IoAllocateMdl() always returned NULL - kern_windrv.c:windrv_unload() wasn't releasing private driver object extensions correctly (found thanks to memguard) This has only been tested with the driver for the Broadcom 802.11g chipset, which was the only Windows/x86-64 driver I could find. Notes: svn path=/head/; revision=141963
* Merge in patch to support AP scanning via ifconfig and the newBill Paul2005-02-111-0/+127
| | | | | | | | | net80211 API. Submitted by: Stephane E. Potvin sepotvin at videotron dot ca Notes: svn path=/head/; revision=141677
* Next step on the road to IRPs: create and use an imitation of theBill Paul2005-02-084-36/+122
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Windows DRIVER_OBJECT and DEVICE_OBJECT mechanism so that we can simulate driver stacking. In Windows, each loaded driver image is attached to a DRIVER_OBJECT structure. Windows uses the registry to match up a given vendor/device ID combination with a corresponding DRIVER_OBJECT. When a driver image is first loaded, its DriverEntry() routine is invoked, which sets up the AddDevice() function pointer in the DRIVER_OBJECT and creates a dispatch table (based on IRP major codes). When a Windows bus driver detects a new device, it creates a Physical Device Object (PDO) for it. This is a DEVICE_OBJECT structure, with semantics analagous to that of a device_t in FreeBSD. The Windows PNP manager will invoke the driver's AddDevice() function and pass it pointers to the DRIVER_OBJECT and the PDO. The AddDevice() function then creates a new DRIVER_OBJECT structure of its own. This is known as the Functional Device Object (FDO) and corresponds roughly to a private softc instance. The driver uses IoAttachDeviceToDeviceStack() to add this device object to the driver stack for this PDO. Subsequent drivers (called filter drivers in Windows-speak) can be loaded which add themselves to the stack. When someone issues an IRP to a device, it travel along the stack passing through several possible filter drivers until it reaches the functional driver (which actually knows how to talk to the hardware) at which point it will be completed. This is how Windows achieves driver layering. Project Evil now simulates most of this. if_ndis now has a modevent handler which will use MOD_LOAD and MOD_UNLOAD events to drive the creation and destruction of DRIVER_OBJECTs. (The load event also does the relocation/dynalinking of the image.) We don't have a registry, so the DRIVER_OBJECTS are stored in a linked list for now. Eventually, the list entry will contain the vendor/device ID list extracted from the .INF file. When ndis_probe() is called and detectes a supported device, it will create a PDO for the device instance and attach it to the DRIVER_OBJECT just as in Windows. ndis_attach() will then call our NdisAddDevice() handler to create the FDO. The NDIS miniport block is now a device extension hung off the FDO, just as it is in Windows. The miniport characteristics table is now an extension hung off the DRIVER_OBJECT as well (the characteristics are the same for all devices handled by a given driver, so they don't need to be per-instance.) We also do an IoAttachDeviceToDeviceStack() to put the FDO on the stack for the PDO. There are a couple of fake bus drivers created for the PCI and pccard buses. Eventually, there will be one for USB, which will actually accept USB IRP.s Things should still work just as before, only now we do things in the proper order and maintain the correct framework to support passing IRPs between drivers. Various changes: - corrected the comments about IRQL handling in subr_hal.c to more accurately reflect reality - update ndiscvt to make the drv_data symbol in ndis_driver_data.h a global so that if_ndis_pci.o and/or if_ndis_pccard.o can see it. - Obtain the softc pointer from the miniport block by referencing the PDO rather than a private pointer of our own (nmb_ifp is no longer used) - implement IoAttachDeviceToDeviceStack(), IoDetachDevice(), IoGetAttachedDevice(), IoAllocateDriverObjectExtension(), IoGetDriverObjectExtension(), IoCreateDevice(), IoDeleteDevice(), IoAllocateIrp(), IoReuseIrp(), IoMakeAssociatedIrp(), IoFreeIrp(), IoInitializeIrp() - fix a few mistakes in the driver_object and device_object definitions - add a new module, kern_windrv.c, to handle the driver registration and relocation/dynalinkign duties (which don't really belong in kern_ndis.c). - made ndis_block and ndis_chars in the ndis_softc stucture pointers and modified all references to it - fixed NdisMRegisterMiniport() and NdisInitializeWrapper() so they work correctly with the new driver_object mechanism - changed ndis_attach() to call NdisAddDevice() instead of ndis_load_driver() (which is now deprecated) - used ExAllocatePoolWithTag()/ExFreePool() in lookaside list routines instead of kludged up alloc/free routines - added kern_windrv.c to sys/modules/ndis/Makefile and files.i386. Notes: svn path=/head/; revision=141524
* Begin the first phase of trying to add IRP support (and ultimatelyBill Paul2005-01-241-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | USB device support): - Convert all of my locally chosen function names to their actual Windows equivalents, where applicable. This is a big no-op change since it doesn't affect functionality, but it helps avoid a bit of confusion (it's now a lot easier to see which functions are emulated Windows API routines and which are just locally defined). - Turn ndis_buffer into an mdl, like it should have been. The structure is the same, but now it belongs to the subr_ntoskrnl module. - Implement a bunch of MDL handling macros from Windows and use them where applicable. - Correct the implementation of IoFreeMdl(). - Properly implement IoAllocateMdl() and MmBuildMdlForNonPagedPool(). - Add the definitions for struct irp and struct driver_object. - Add IMPORT_FUNC() and IMPORT_FUNC_MAP() macros to make formatting the module function tables a little cleaner. (Should also help with AMD64 support later on.) - Fix if_ndis.c to use KeRaiseIrql() and KeLowerIrql() instead of the previous calls to hal_raise_irql() and hal_lower_irql() which have been renamed. The function renaming generated a lot of churn here, but there should be very little operational effect. Notes: svn path=/head/; revision=140751
* Start each of the license/copyright comments with /*-, minor shuffle of linesWarner Losh2005-01-064-4/+4
| | | | Notes: svn path=/head/; revision=139749
* record the bssid for an associationSam Leffler2004-12-121-0/+1
| | | | | | | Tested by: Daniel O'Connor Notes: svn path=/head/; revision=138728
* Fix compilation and correct mapping from struct ifnet toSam Leffler2004-12-101-7/+9
| | | | | | | | | struct ieee80211com after net80211 import. Submitted by: Tor Egge Notes: svn path=/head/; revision=138641
* Update for net80211 changes.Sam Leffler2004-12-082-17/+17
| | | | Notes: svn path=/head/; revision=138572
* Drop the NDIS lock before returning from ndis_start().Lukas Ertl2004-10-181-1/+3
| | | | | | | | | PR: i386/72795 Submitted by: Frank Mayhar <frank@exit.com> MFC in: 3 days Notes: svn path=/head/; revision=136677
* Fix sis, bfe and ndis in the same way dc was fixed:Max Laier2004-10-081-0/+3
| | | | | | | | | | Do not tell the hardware to send when there were no packets enqueued. Found and reviewed by: green MFC after: 1 days Notes: svn path=/head/; revision=136269
* Make the Texas Instruments 802.11g chipset work with the NDISulator.Bill Paul2004-08-161-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This was tested with a Netgear WG311v2 802.11b/g PCI card. Things that were fixed: - This chip has two memory mapped regions, one at PCIR_BAR(0) and the other at PCIR_BAR(1). This is a little different from the other chips I've seen with two PCI shared memory regions, since they tend to have the second BAR ad PCIR_BAR(2). if_ndis_pci.c tests explicitly for PCIR_BAR(2). This has been changed to simply fill in ndis_res_mem first and ndis_res_altmem second, if a second shared memory range exists. Given that NDIS drivers seem to scan for BARs in ascending order, I think this should be ok. - Fixed the code that tries to process firmware images that have been loaded as .ko files. To save a step, I was setting up the address mapping in ndis_open_file(), but ndis_map_file() flags pre-existing mappings as an error (to avoid duplicate mappings). Changed this so that the mapping is now donw in ndis_map_file() as expected. - Made the typedef for 'driver_entry' explicitly include __stdcall to silence gcc warning in ndis_load_driver(). NOTE: the Texas Instruments ACX111 driver needs firmware. With my card, there were 3 .bin files shipped with the driver. You must either put these files in /compat/ndis or convert them with ndiscvt -f and kldload them so the driver can use them. Without the firmware image, the NIC won't work. Notes: svn path=/head/; revision=133876
* Minor cleanups:Bill Paul2004-08-031-2/+8
| | | | | | | | | - Fix typo in comment - Remember to free() sc->ndis_txarray on detach - Remember to do an ifmedia_removeall() for ethernet devices Notes: svn path=/head/; revision=133080
* Second part of ALTQ driver modifications, covering:Max Laier2004-08-011-0/+19
| | | | | | | | | | | | | an(4), ath(4), hme(4), ndis(4), vr(4) and wi(4) Please help testing: http://people.freebsd.org/~mlaier/ALTQ_driver/ Tested by: Vaidas Damosevicius (an, ath, wi) Roman Divacky (vr) Submitted by: yongari (hme) Notes: svn path=/head/; revision=132986
* The watchdog callout executes with the (non-sleepable) ifnet lock heldBill Paul2004-08-011-1/+1
| | | | | | | | | | now, but it's possible for ndis_reset_nic() to sleep (sometimes the MiniportReset() method returns NDIS_STATUS_PENDING and we have to wait for completion). To get around this, execute the ndis_reset_nic() routine in the NDIS_TASKQUEUE thread. Notes: svn path=/head/; revision=132983
* Add some minor changes related to PCMCIA attribute memory mappingBill Paul2004-08-011-2/+18
| | | | | | | | | (which I apparently forgot to commit earlier). Acquire NDIS_LOCK() in ndis_linksts_done(). Notes: svn path=/head/; revision=132953
* Make NdisReadPcmciaAttributeMemory() and NdisWritePcmciaAttributeMemory()Bill Paul2004-07-113-22/+75
| | | | | | | | | | | | | | | | | | | | | | | | | | actually work. Make the PCI and PCCARD attachments provide a bus_get_resource_list() method so that resource listing for PCCARD works. PCCARD does not have a bus_get_resource_list() method (yet), so I faked up the resource list management in if_ndis_pccard.c, and added bus_get_resource_list() methods to both if_ndis_pccard.c and if_ndis_pci.c. The one in the PCI attechment just hands off to the PCI bus code. The difference is transparent to the NDIS resource handler code. Fixed ndis_open_file() so that opening files which live on NFS filesystems work: pass an actual ucred structure to VOP_GETATTR() (NFS explodes if the ucred structure is NOCRED). Make NdisMMapIoSpace() handle mapping of PCMCIA attribute memory resources correctly. Turn subr_ndis.c:my_strcasecmp() into ndis_strcasecmp() and export it so that if_ndis_pccard.c can use it, and junk the other copy of my_strcasecmp() from if_ndis_pccard.c. Notes: svn path=/head/; revision=131953
* Fix two problems:Bill Paul2004-07-072-13/+13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | - In subr_ndis.c:ndis_allocate_sharemem(), create the busdma tags used for shared memory allocations with a lowaddr of 0x3E7FFFFF. This forces the buffers to be mapped to physical/bus addresses within the first 1GB of physical memory. It seems that at least one card (Linksys Instant Wireless PCI V2.7) depends on this behavior. I don't know if this is a hardware restriction, or if the NDIS driver for this card is truncating the addresses itself, but using physical/bus addresses beyong the 1GB limit causes initialization failures. - Create am NDIS_INITIALIZED() macro in if_ndisvar.h and use it in if_ndis.c to test whether the device has been initialized rather than checking for the presence of the IFF_UP flag in if_flags. While debugging the previous problem, I noticed that bringing up the device would always produce failures from ndis_setmulti(). It turns out that the following steps now occur during device initialization: - IFF_UP flag is set in if_flags - ifp->if_ioctl() called with SIOCSIFADDR (which we don't handle) - ifp->if_ioctl() called with SIOCADDMULTI - ifp->if_ioctl() called with SIOCADDMULTI (again) - ifp->if_ioctl() called with SIOCADDMULTI (yet again) - ifp->if_ioctl() called with SIOCSIFFLAGS Setting the receive filter and multicast filters can only be done when the underlying NDIS driver has been initialized, which is done by ifp->if_init(). However, we don't call ifp->if_init() until ifp->if_ioctl() is called with SIOCSIFFLAGS and IFF_UP has been set. It appears that now, the network stack tries to add multicast addresses to interface's filter before those steps occur. Normally, ndis_setmulti() would trap this condition by checking for the IFF_UP flag, but the network code has in fact set this flag already, so ndis_setmulti() is fooled into thinking the interface has been initialized when it really hasn't. It turns out this is usually harmless because the ifp->if_init() routine (in this case ndis_init()) will set up the multicast filter when it initializes the hardware anyway, and the underlying routines (ndis_get_info()/ndis_set_info()) know that the driver/NIC haven't been initialized yet, but you end up spurious error messages on the console all the time. Something tells me this new behavior isn't really correct. I think the intention was to fix it so that ifp->if_init() is only called once when we ifconfig an interface up, but the end result seems a little bogus: the change of the IFF_UP flag should be propagated down to the driver before calling any other ioctl() that might actually require the hardware to be up and running. Notes: svn path=/head/; revision=131750
* Take advantage of the dev sysctl tree.Dag-Erling Smørgrav2004-06-042-0/+8
| | | | | | | Approved by: wpaul Notes: svn path=/head/; revision=130097
* Unbreak the Intel 2100 Centrino wireless driver (and probably others):Bill Paul2004-06-041-7/+12
| | | | | | | | | | | | | | | | | | | | | | | | - In subr_ndis.c, my_strcasecmp() actually behaved like my_strncasecmp(): we really need it to behave like the former, not the latter. (It was falsely matching "RadioEnable", which defaults to 1 with "RadioEnableHW" which the driver creates itself and to 0, because we were using strlen("RadioEnable") as the length to test. This caused the radio to always be turned off. :( ) - In if_ndis.c, only set IEEE80211_CHAN_A for channels if we actually set any IEEE80211_MODE_11A rates. (ieee80211_attach() will "helpfully" add IEEE80211_MODE_11A to ic_modecaps for you if you initialize any 802.11a channels. This caused "ndis0: 11a rates:" to erroneously be displayed during driver load.) - Also in if_ndis.c, when using TESTSETRATE() to add in any missing 802.11b rates, remember to OR the rates with IEEE80211_RATE_BASIC, otherwise comparing against existing basic rates won't match. (1, 2, 5.5 and 11Mbps are basic rates, according to the 802.11b spec.) This erroneously cause 11Mbps to be added to the 11b rate list twice. Notes: svn path=/head/; revision=130051
* Explicitly #include <sys/module.h> in these files too (they useBill Paul2004-06-012-0/+2
| | | | | | | MODULE_DEPEND()). Notes: svn path=/head/; revision=129972
* In subr_ndis.c, when searching for keys in our make-pretend registry,Bill Paul2004-05-291-3/+50
| | | | | | | | | | | | | | | | | | | | | | | | make the key name matching case-insensitive. There are some drivers and .inf files that have mismatched cases, e.g. the driver will look for "AdhocBand" whereas the .inf file specifies a registry key to be created called "AdHocBand." The mismatch is probably a typo that went undetected (so much for QA), but since Windows seems to be case-insensitive, we should be too. In if_ndis.c, initialize rates and channels correctly so that specify frequences correctly when trying to set channels in the 5Ghz band, and so that 802.11b rates show up for some a/b/g cards (which otherwise appear to have no 802.11b modes). Also, when setting OID_802_11_CONFIGURATION in ndis_80211_setstate(), provide default values for the beacon interval, ATIM window and dwelltime. The Atheros "Aries" driver will crash if you try to select ad-hoc mode and leave the beacon interval set to 0: it blindly uses this value and does a division by 0 in the interrupt handler, causing an integer divide trap. Notes: svn path=/head/; revision=129834
* Restore source code compatibility with 5.2-RELEASE.Bill Paul2004-05-121-0/+4
| | | | Notes: svn path=/head/; revision=129155
* Link state change notification of ethernet media to the routing socket.Andre Oppermann2004-05-061-0/+5
| | | | | | | | | | o The ndis_ticktask() function updates the ifi_link_state field and calls rt_ifmsg() to notify listeners on the routing socket. Approved by: wpaul Notes: svn path=/head/; revision=129002
* Small timer cleanups:Bill Paul2004-04-301-0/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | - Use the dh_inserted member of the dispatch header in the Windows timer structure to indicate that the timer has been "inserted into the timer queue" (i.e. armed via timeout()). Use this as the value to return to the caller in KeCancelTimer(). Previously, I was using callout_pending(), but you can't use that with timeout()/untimeout() without creating a potential race condition. - Make ntoskrnl_init_timer() just a wrapper around ntoskrnl_init_timer_ex() (reduces some code duplication). - Drop Giant when entering if_ndis.c:ndis_tick() and subr_ntorkrnl.c:ntoskrnl_timercall(). At the moment, I'm forced to use system callwheel via timeout()/untimeout() to handle timers rather than the callout API (struct callout is too big to fit inside the Windows struct KTIMER, so I'm kind of hosed). Unfortunately, all the callouts in the callwhere are not marked as MPSAFE, so when one of them fires, it implicitly acquires Giant before invoking the callback routine (and releases it when it returns). I don't need to hold Giant, but there's no way to stop the callout code from acquiring it as long as I'm using timeout()/untimeout(), so for now we cheat by just dropping Giant right away (and re-acquiring it right before the routine returns so keep the callout code happy). At some point, I will need to solve this better, but for now this should be a suitable workaround. Notes: svn path=/head/; revision=128780
* Remove code that fiddles with Giant in ndis_ticktask() that snuck inBill Paul2004-04-281-4/+0
| | | | | | | during previous commit. Notes: svn path=/head/; revision=128719
* Correct KASSERT()s that check for initialization of mutexes in ndis_detach(),Bill Paul2004-04-231-2/+6
| | | | | | | | | which are different now that I'm not using mutex pools anymore. Noticed by: des Notes: svn path=/head/; revision=128585
* Set the INTR_MPSAFE flag.Bill Paul2004-04-221-1/+1
| | | | Notes: svn path=/head/; revision=128565
* Ok, _really_ fix the Intel 2100B Centrino deadlock problems this time.Bill Paul2004-04-221-29/+3
| | | | | | | | | | | | | | | | | | | (I hope.) My original instinct to make ndis_return_packet() asynchronous was correct. Making ndis_rxeof() submit packets to the stack asynchronously fixes one recursive spinlock acquisition, but it's also possible for it to happen via the ndis_txeof() path too. So: - In if_ndis.c, revert ndis_rxeof() to its old behavior (and don't bother putting ndis_rxeof_serial() back since we don't need it anymore). - In kern_ndis.c, make ndis_return_packet() submit the call to the MiniportReturnPacket() function to the "ndis swi" thread so that it always happens in another context no matter who calls it. Notes: svn path=/head/; revision=128546
* Fix the problems people have been having with the Intel 2100B CentrinoBill Paul2004-04-211-107/+19
| | | | | | | | | | | | | | | | | | | | | | | | wireless ever since I added the new spinlock code. Previously, I added a special ndis_rxeof_serial() function to insure that when we receive a packet, we never end up calling the MiniportReturnPacket() routine until after the receive handler has finished. I set things up so that ndis_rxeof_serial() would only be used for serialized miniports since they depend on this property. Well, it turns out deserialized miniports depend on a similar property: you can't let MiniportReturnPacket() be called from the same context as the receive handler at all. The 2100B driver happens to use a single spinlock for all of its synchronization, and it tries to acquire it both while in MiniportHandleInterrupt() and in MiniportReturnPacket(), so if we call MiniportReturnPacket() from the MiniportHandleInterrupt() context, we will end up trying to acquire the spinlock recursively, which you can't do. To fix this, I made the ndis_rxeof_serial() handler the default. An alternate solution would be to make ndis_return_packet() submit the call to MiniportReturnPacket() to the NDIS task queue thread. I may do that in the future, after I've tested things a bit more. Notes: svn path=/head/; revision=128510
* Continue my efforts to imitate Windows as closely as possible byBill Paul2004-04-142-50/+47
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior. Notes: svn path=/head/; revision=128229
* - The MiniportReset() function can return NDIS_STATUS_PENDING, in whichBill Paul2004-04-051-36/+37
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | case we should wait for the resetdone handler to be called before returning. - When providing resources via ndis_query_resources(), uses the computed rsclen when using bcopy() to copy out the resource data rather than the caller-supplied buffer length. - Avoid using ndis_reset_nic() in if_ndis.c unless we really need to reset the NIC because of a problem. - Allow interrupts to be fielded during ndis_attach(), at least as far as allowing ndis_isr() and ndis_intrhand() to run. - Use ndis_80211_rates_ex when probing for supported rates. Technically, this isn't supposed to work since, although Microsoft added the extended rate structure with the NDIS 5.1 update, the spec still says that the OID_802_11_SUPPORTED_RATES OID uses ndis_80211_rates. In spite of this, it appears some drivers use it anyway. - When adding in our guessed rates, check to see if they already exist so that we avoid any duplicates. - Add a printf() to ndis_open_file() that alerts the user when a driver attempts to open a file under /compat/ndis. With these changes, I can get the driver for the SMC 2802W 54g PCI card to load and run. This board uses a Prism54G chip. Note that in order for this driver to work, you must place the supplied smc2802w.arm firmware image under /compat/ndis. (The firmware is not resident on the device.) Note that this should also allow the 3Com 3CRWE154G72 card to work as well; as far as I can tell, these cards also use a Prism54G chip. Notes: svn path=/head/; revision=127887
* Add missing cprd_flags member to partial resource structure inBill Paul2004-03-291-0/+2
| | | | | | | | | | | | | | | | resource_var.h. In kern_ndis.c:ndis_convert_res(), fill in the cprd_flags and cprd_sharedisp fields as best we can. In if_ndis.c:ndis_setmulti(), don't bother updating the multicast filter if our multicast address list is empty. Add some missing updates to ndis_var.h and ntoskrnl_var.h that I forgot to check in when I added the KeDpc stuff. Notes: svn path=/head/; revision=127552
* The ndis_wlan_bssid_ex structure we retrieve in ndis_get_assoc() isBill Paul2004-03-241-5/+11
| | | | | | | | | | | | | variable length, so we should not be trying to copy it into a fixed length buffer, especially one on the stack. malloc() a buffer of the right size and return a pointer to that instead. Fixes a crash I discovered when testing whe a Cisco AP in infrastructure mode, which returns several information elements that make the ndis_wlan_bssid_ex structure larger than expected. Notes: svn path=/head/; revision=127349