Commit Graph

219 Commits

Author SHA1 Message Date
wpaul
0adcaff459 Unbreak the Intel 2100 Centrino wireless driver (and probably others):
- 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.
2004-06-04 04:43:36 +00:00
wpaul
da796b8f8e Explicitly #include <sys/module.h> in these files too (they use
MODULE_DEPEND()).
2004-06-01 23:27:36 +00:00
wpaul
86ad4bc572 In subr_ndis.c, when searching for keys in our make-pretend registry,
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.
2004-05-29 06:41:17 +00:00
wpaul
08110a92f0 Restore source code compatibility with 5.2-RELEASE. 2004-05-12 15:58:42 +00:00
andre
1769ff7c1f Link state change notification of ethernet media to the routing socket.
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
2004-05-06 13:17:02 +00:00
wpaul
a7f0f62fc0 Small timer cleanups:
- 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.
2004-04-30 20:51:55 +00:00
wpaul
5cd0d2d78c Remove code that fiddles with Giant in ndis_ticktask() that snuck in
during previous commit.
2004-04-28 17:06:18 +00:00
wpaul
1291cc3eae Correct KASSERT()s that check for initialization of mutexes in ndis_detach(),
which are different now that I'm not using mutex pools anymore.

Noticed by: des
2004-04-23 17:15:14 +00:00
wpaul
8e27464c81 Set the INTR_MPSAFE flag. 2004-04-22 21:49:18 +00:00
wpaul
6bc1da1c05 Ok, _really_ fix the Intel 2100B Centrino deadlock problems this time.
(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.
2004-04-22 07:08:39 +00:00
wpaul
4b52f76c1d Fix the problems people have been having with the Intel 2100B Centrino
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.
2004-04-21 02:29:28 +00:00
wpaul
9765d24df6 Continue my efforts to imitate Windows as closely as possible by
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.
2004-04-14 07:48:03 +00:00
wpaul
e8bf917ce6 - The MiniportReset() function can return NDIS_STATUS_PENDING, in which
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.
2004-04-05 08:26:52 +00:00
wpaul
163b236504 Add missing cprd_flags member to partial resource structure in
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.
2004-03-29 02:15:29 +00:00
wpaul
029bb98d76 The ndis_wlan_bssid_ex structure we retrieve in ndis_get_assoc() is
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.
2004-03-24 05:35:03 +00:00
wpaul
8237685662 Recently I realized that the ADMtek 8211 driver wasn't working correctly
(NIC would claim to establish a link with an ad-hoc net but it couldn't
send/receive packets). It turns out that every time the checkforhang
handler was called by ndis_ticktask(), the driver would generate a new
media connect event. The NDIS spec says the checkforhang handler is
called "approximately every 2 seconds" but using exactly 2 seconds seems
too fast. Using 3 seconds makes it happy again, so we'll go with that
for now.
2004-03-23 19:51:17 +00:00
wpaul
6e0e8aa047 Make if_ndis_pci.c and if_ndis_pccard.c use bus_alloc_resource() again
instead of bus_alloc_resource_any() to restore source compatibility
with 5.2-REL and 5.2.1-REL systems. bus_alloc_resource_any() doesn't
really do anything besides hide some of bus_alloc_resource()'s arguments
from us, and in my opinion this isn't worth breaking backwards
compatibility for people who want to use the NDISulator code on 5.2.x.
2004-03-21 19:56:41 +00:00
wpaul
14202432d8 Fix another Intel 2200BG bug: don't schedule ndis_ticktask() on media
disconnect events if the link wasn't even up yet.
2004-03-21 00:06:56 +00:00
wpaul
8feaa1f450 - Rewrite the timer and event API routines in subr_ndis.c so that they
are actually layered on top of the KeTimer API in subr_ntoskrnl.c, just
  as it is in Windows. This reduces code duplication and more closely
  imitates the way things are done in Windows.

- Modify ndis_encode_parm() to deal with the case where we have
  a registry key expressed as a hex value ("0x1") which is being
  read via NdisReadConfiguration() as an int. Previously, we tried
  to decode things like "0x1" with strtol() using a base of 10, which
  would always yield 0. This is what was causing problems with the
  Intel 2200BG Centrino 802.11g driver: the .inf file that comes
  with it has a key called RadioEnable with a value of 0x1. We
  incorrectly decoded this value to '0' when it was queried, hence
  the driver thought we wanted the radio turned off.

- In if_ndis.c, most drivers don't accept NDIS_80211_AUTHMODE_AUTO,
  but NDIS_80211_AUTHMODE_SHARED may not be right in some cases,
  so for now always use NDIS_80211_AUTHMODE_OPEN.

NOTE: There is still one problem with the Intel 2200BG driver: it
happens that the kernel stack in Windows is larger than the kernel
stack in FreeBSD. The 2200BG driver sometimes eats up more than 2
pages of stack space, which can lead to a double fault panic.
For the moment, I got things to work by adding the following to
my kernel config file:

options         KSTACK_PAGES=8

I'm pretty sure 8 is too big; I just picked this value out of a hat
as a test, and it happened to work, so I left it. 4 pages might be
enough. Unfortunately, I don't think you can dynamically give a
thread a larger stack, so I'm not sure how to handle this short of
putting a note in the man page about it and dealing with the flood
of mail from people who never read man pages.
2004-03-20 23:39:43 +00:00
mdodd
2ff0565c54 Don't announce MAC addresses twice.
(ieee80211_ifattach() calls ether_ifattach().)
2004-03-20 19:57:47 +00:00
njl
05a1f56fc9 Convert callers to the new bus_alloc_resource_any(9) API.
Submitted by:	Mark Santcroos <marks@ripe.net>
Reviewed by:	imp, dfr, bde
2004-03-17 17:50:55 +00:00
mux
30b04535e7 Don't set ifp->if_output to ether_output(), since ether_ifattach()
will do it for us (we either call ether_ifattach() directly, or it
gets called within ieee80211_ifattach()).

Approved by:	wpaul
2004-03-12 17:05:06 +00:00
wpaul
f068497517 Fix the problem with the Cisco Aironet 340 PCMCIA card. Most newer drivers
for Windows are deserialized miniports. Such drivers maintain their own
queues and do their own locking. This particular driver is not deserialized
though, and we need special support to handle it correctly.

Typically, in the ndis_rxeof() handler, we pass all incoming packets
directly to (*ifp->if_input)(). This in turn may cause another thread
to run and preempt us, and the packet may actually be processed and
then released before we even exit the ndis_rxeof() routine. The
problem with this is that releasing a packet calls the ndis_return_packet()
function, which hands the packet and its buffers back to the driver.
Calling ndis_return_packet() before ndis_rxeof() returns will screw
up the driver's internal queues since, not being deserialized,
it does no locking.

To avoid this problem, if we detect a serialized driver (by checking
the attribute flags passed to NdisSetAttributesEx(), we use an alternate
ndis_rxeof() handler, ndis_rxeof_serial(), which puts the call to
(*ifp->if_input)() on the NDIS SWI work queue. This guarantees the
packet won't be processed until after ndis_rxeof_serial() returns.

Note that another approach is to always copy the packet data into
another mbuf and just let the driver retain ownership of the ndis_packet
structure (ndis_return_packet() never needs to be called in this
case). I'm not sure which method is faster.
2004-03-11 09:40:00 +00:00
wpaul
9d87e57eb4 Trim unneeded includes from if_ndis_pccard.c and if_ndis_pci.c. Also removed
unused variables from if_ndis_pccard.c
2004-03-09 20:29:21 +00:00
wpaul
696d0d4e7f If the resource listing obtained from BUS_GET_RESOURCE_LIST() in
ndis_probe_pci() doesn't contain an entry for an IRQ resource, try to
force one to be routed to us anyway by adding an extra call to
bus_alloc_resource(). If this fails, then we have to abort the attach.

Patch provided by jhb, tweaked by me.
2004-03-09 18:39:40 +00:00
wpaul
7a42ffc382 Add preliminary support for PCMCIA devices in addition to PCI/cardbus.
if_ndis.c has been split into if_ndis_pci.c and if_ndis_pccard.c.
The ndiscvt(8) utility should be able to parse device info for PCMCIA
devices now. The ndis_alloc_amem() has moved from kern_ndis.c to
if_ndis_pccard.c so that kern_ndis.c no longer depends on pccard.

NOTE: this stuff is not guaranteed to work 100% correctly yet. So
far I have been able to load/init my PCMCIA Cisco Aironet 340 card,
but it crashes in the interrupt handler. The existing support for
PCI/cardbus devices should still work as before.
2004-03-07 02:49:06 +00:00
wpaul
04e0838d2b Add yet more bulletproofing. This is to guard against the case that
ndis_init_nic() works one during attach, but fails later. Many things
will blow up if ndis_init_nic() fails and we aren't careful.
2004-02-11 21:53:40 +00:00
wpaul
3b12a6e6bd Don't hold NDIS_LOCK() around call to ndis_getstate_80211() since it
may block on ndis_get_info().
2004-02-07 23:52:58 +00:00
wpaul
cad1573762 Implement support for single packet sends. The Intel Centrino driver
that Asus provides on its CDs has both a MiniportSend() routine
and a MiniportSendPackets() function. The Microsoft NDIS docs say
that if a driver has both, only the MiniportSendPackets() routine
will be used. Although I think I implemented the support correctly,
calling the MiniportSend() routine seems to result in no packets going
out on the air, even though no error status is returned. The
MiniportSendPackets() function does work though, so at least in
this case it doesn't matter.

In if_ndis.c:ndis_getstate_80211(), if ndis_get_assoc() returns
an error, don't bother trying to obtain any other state since the
calls may fail, or worse cause the underlying driver to crash.

(The above two changes make the Asus-supplied Centrino work.)

Also, when calling the OID_802_11_CONFIGURATION OID, remember
to initialize the structure lengths correctly.

In subr_ndis.c:ndis_open_file(), set the current working directory
to rootvnode if we're in a thread that doesn't have a current
working directory set.
2004-02-03 07:39:23 +00:00
wpaul
1fc97b3c26 Use the OID_802_11_CONFIGURATION OID when deciding if the underlying driver
is for an 802.11 device or not. At least one driver I have does not
support the OID_802_11_NETWORK_TYPES_SUPPORTED OID.

Also, for now, don't do anything special in the ndis_suspend() method.
I originally wanted to shut down the NIC but leave the IFF_UP flag alone
since technically the interface is meant to remain up, but an interrupt
may be delivered to the ISR on suspend, and if this happens while the
NIC is halted, we will crash, since none of the miniport driver methods
will function.

This needs to be dealt with properly later, but for now this prevents
a panic, and the resume method properly re-inits the NIC.
2004-02-01 21:35:15 +00:00
wpaul
547b42ac2e Go back to using AUTHMODE_AUTO if WEP is on. In some cases, the Centrino
won't associate in BSS mode if you use AUTHMODE_SHARED. I probably don't
understand enough to know when SHARED should be used vs. OPEN or WPA.
For now, go back to what works.
2004-01-29 03:16:58 +00:00
wpaul
0d9244785d This should have been checked in as part of the last update to if_ndis.c:
add yet another member to the ndis_softc as part of the workaround for
the net80211 dain bramage.
2004-01-27 09:08:12 +00:00
wpaul
cc4f21e732 Add a kludge to avoid having ndis_init() called needlessly by dhclient
on an SIOCSIFADDR (by way of brain damage in net80211).

Also, avoid trying to set NDIS_80211_AUTHMODE_AUTO since the Microsoft
documentation I have recommends not using it, and the Centrino driver
seems to dislike being told to use it.
2004-01-27 07:57:42 +00:00
wpaul
6d190d0786 Use the M_BZERO flag with malloc() in a couple of places. 2004-01-27 03:14:59 +00:00
wpaul
983ec1a4d4 Correct KASSERT() in ndis_destroy(): ndis_mtx is a pointer now.
Also add KASSERT() for ndis_intrmtx().
2004-01-25 00:13:07 +00:00
wpaul
e5e785e0d4 Add missing newlines to some device_printf()s.
Don't do anything in ndis_get_assoc() if the link isn't up (avoids
spurrious "couldn't get bssid" messages on the console).
2004-01-24 02:48:22 +00:00
wpaul
c46d660722 Add suspend and resume methods. I'm not certain this work correctly
since I can't easily test them on my laptop right now, but they
should do the right thing.
2004-01-22 03:00:59 +00:00
wpaul
39e6c1e2a7 Add support for TCP/IP checksum offload.
No, really.
2004-01-22 02:36:34 +00:00
wpaul
687bdc6939 Correct instances of mtx_lock()/mtx_unlock() that should have been
mtx_pool_lock()/mtx_pool_unlock().
2004-01-20 08:19:42 +00:00
wpaul
a5104c2f15 Properly program the multicast filter in ndis_setmulti(),
and fix promisc mode in ndis_ioctl().
2004-01-19 07:03:46 +00:00
wpaul
2bcdd99de4 Convert from using taskqueue_swi to using private kernel threads. The
problem with using taskqueue_swi is that some of the things we defer
into threads might block for up to several seconds. This is an unfriendly
thing to do to taskqueue_swi, since it is assumed the taskqueue threads
will execute fairly quickly once a task is submitted. Reorganized the
locking in if_ndis.c in the process.

Cleaned up ndis_write_cfg() and ndis_decode_parm() a little.
2004-01-18 22:57:11 +00:00
wpaul
dfae368ae8 The definition for __stdcall logically belongs in pe_var.h, but
the definitions for NDIS_BUS_SPACE_IO and NDIS_BUS_SPACE_MEM logically
belong in hal_var.h. At least, that's my story, and I'm sticking to it.

Also, remove definition of __stdcall from if_ndis.c now that it's pulled
in from pe_var.h.
2004-01-15 21:31:49 +00:00
wpaul
2c0e413ccc Ugh. Last commit went horribly wrong. Back out changes to subr_ntoskrnl.c,
make sure if_ndis.c really gets checked in this time.
2004-01-12 21:04:43 +00:00
wpaul
fcdf650572 Merge in some changes submitted by Brian Feldman. Among other things,
these add support for listing BSSIDs via wicontrol -l. I added code
to call OID_802_11_BSSID_LIST_SCAN to allow scanning for any nearby
wirelsss nets.

Convert from using individual mutexes to a mutex pool, created in
subr_ndis.c. This deals with the problem of drivers creating locks
in their DriverEntry() routines which might get trashed later.

Put some messages under IFF_DEBUG.
2004-01-12 03:49:20 +00:00
wpaul
1d43d52f79 The private data section of ndis_packets has a 'packet flags' byte
which has two important flags in it: the 'allocated by NDIS' flag
and the 'media specific info present' flag. There are two Windows macros
for getting/setting media specific info fields within the ndis_packet
structure which can behave improperly if these flags are not initialized
correctly when a packet is allocated. It seems the correct thing
to do is always set the NDIS_PACKET_ALLOCATED_BY_NDIS flag on
all newly allocated packets.

This fixes the crashes with the Intel Centrino wireless driver.
My sample card now seems to work correctly.

Also, fix a potential LOR involving ndis_txeof() in if_ndis.c.
2004-01-09 06:53:49 +00:00
wpaul
de79d89d37 Correct the definition of the ndis_miniport_interrupt structure:
the ni_dpccountlock member is an ndis_kspin_lock, not an
ndis_spin_lock (the latter is too big).

Run if_ndis.c:ndis_tick() via taskqueue_schedule(). Also run
ndis_start() via taskqueue in certain circumstances.

Using these tweaks, I can now get the Broadcom BCM5701 NDIS
driver to load and run. Unfortunately, the version I have seems
to suffer from the same bug as the SMC 83820 driver, which is
that it creates a spinlock during its DriverEntry() routine.
I'm still debating the right way to deal with this.
2004-01-08 10:44:37 +00:00
wpaul
7452e76589 - Add pe_get_message() and pe_get_messagetable() for processing
the RT_MESSAGETABLE resources that some driver binaries have.
  This allows us to print error messages in ndis_syslog().

- Correct the implementation of InterlockedIncrement() and
  InterlockedDecrement() -- they return uint32_t, not void.

- Correct the declarations of the 64-bit arithmetic shift
  routines in subr_ntoskrnl.c (_allshr, allshl, etc...). These
  do not follow the _stdcall convention: instead, they appear
  to be __attribute__((regparm(3)).

- Change the implementation of KeInitializeSpinLock(). There is
  no complementary KeFreeSpinLock() function, so creating a new
  mutex on each call to KeInitializeSpinLock() leaks resources
  when a driver is unloaded. For now, KeInitializeSpinLock()
  returns a handle to the ntoskrnl interlock mutex.

- Use a driver's MiniportDisableInterrupt() and MiniportEnableInterrupt()
  routines if they exist. I'm not sure if I'm doing this right
  yet, but at the very least this shouldn't break any currently
  working drivers, and it makes the Intel PRO/1000 driver work.

- In ndis_register_intr(), save some state that might be needed
  later, and save a pointer to the driver's interrupt structure
  in the ndis_miniport_block.

- Save a pointer to the driver image for use by ndis_syslog()
  when it calls pe_get_message().
2004-01-06 07:09:26 +00:00
wpaul
389bb3f274 Modify if_ndis.c so that the MiniportISR function runs in ndis_intr()
and MiniportHandleInterrupt() is fired off later via a task queue in
ndis_intrtask(). This more accurately follows the NDIS interrupt handling
model, where the ISR does a minimal amount of work in interrupt context
and the handler is defered and run at a lower priority.

Create a separate ndis_intrmtx mutex just for the guarding the ISR.

Modify NdisSynchronizeWithInterrupt() to aquire the ndis_intrmtx
mutex before invoking the synchronized procedure. (The purpose of
this function is to provide mutual exclusion for code that shares
variables with the ISR.)

Modify NdisMRegisterInterrupt() to save a pointer to the miniport
block in the ndis_miniport_interrupt structure so that
NdisSynchronizeWithInterrupt() can grab it later and derive
ndis_intrmtx from it.
2004-01-04 21:22:25 +00:00
wpaul
cc0f677dae In ndis_attach(), report the NDIS API level that the Windows miniport
driver was compiled with.

Remove debug printf from ndis_assicn_pcirsc(). It doesn't serve
much purpose.

Implement NdisMIndicateStatus() and NdisMIndicateStatusComplete()
as functions in subr_ndis.c. In NDIS 4.0, they were functions. In
NDIS 5.0 and later, they're just macros.

Allocate a few extra packets/buffers beyond what the driver asks
for since sometimes it seems they can lie about how many they really
need, and some extra stupid ones don't check to see if NdisAllocatePacket()
and/or NdisAllocateBuffer() actually succeed.
2004-01-04 03:00:21 +00:00
wpaul
79a95fe15c In if_ndis.c:ndis_attach(), temporarily set the IFF_UP flag while
calling the haltfunc. If an interrupt is triggered by the init
or halt func, the IFF_UP flag must be set in order for us to be able
to service it.

In kern_ndis.c: implement a handler for NdisMSendResourcesAvailable()
(currently does nothing since we don't really need it).

In subr_ndis.c:
	- Correct ndis_init_string() and ndis_unicode_to_ansi(),
	  which were both horribly broken.
        - Implement NdisImmediateReadPciSlotInformation() and
	  NdisImmediateWritePciSlotInformation().
	- Implement NdisBufferLength().
	- Work around my first confirmed NDIS driver bug.
	  The SMC 9462 gigE driver (natsemi 83820-based copper)
	  incorrectly creates a spinlock in its DriverEntry()
	  routine and then destroys it in its MiniportHalt()
	  handler. This is wrong: spinlocks should be created
	  in MiniportInit(). In a Windows environment, this is
	  often not a problem because DriverEntry()/MiniportInit()
	  are called once when the system boots and MiniportHalt()
	  or the shutdown handler is called when the system halts.

With this stuff in place, this driver now seems to work:

ndis0: <SMC EZ Card 1000> port 0xe000-0xe0ff mem 0xda000000-0xda000fff irq 10 at device 9.0 on pci0
ndis0: assign PCI resources...
ndis_open_file("FLASH9.hex", 18446744073709551615)
ndis0: Ethernet address: 00:04:e2:0e:d3:f0
2004-01-03 13:20:30 +00:00
wpaul
29f6674338 Clean up ndiscvt a bit (leaving out the -i flag didn't work) and add
copyrights to the inf parser files.

Add a -n flag to ndiscvt to allow the user to override the default
device name of NDIS devices. Instead of "ndis0, ndis1, etc..."
you can have "foo0, foo1, etc..." This allows you to have more than
one kind of NDIS device in the kernel at the same time.

Convert from printf() to device_printf() in if_ndis.c, kern_ndis.c
and subr_ndis.c.

Create UMA zones for ndis_packet and ndis_buffer structs allocated
on transmit. The zones are created and destroyed in the modevent
handler in kern_ndis.c.

printf() and UMA changes submitted by green@freebsd.org
2004-01-02 04:31:06 +00:00
wpaul
b56a5ed44a - subr_ntoskrnl.c: improve the _fastcall hack based on suggestions from
peter and jhb: use __volatile__ to prevent gcc from possibly reordering
  code, use a null inline instruction instead of a no-op movl (I would
  have done this myself if I knew it was allowed) and combine two register
  assignments into a single asm statement.
- if_ndis.c: set the NDIS_STATUS_PENDING flag on all outgoing packets
  in ndis_start(), make the resource allocation code a little smarter
  about how it selects the altmem range, correct a lock order reversal
  in ndis_tick().
2003-12-31 04:12:57 +00:00
wpaul
bd547ce3e3 - Add new 802.11 OID information obtained from NDIS 5.1 update to
ndis_var.h
- In kern_ndis.c:ndis_send_packets(), avoid dereferencing NULL pointers
  created when the driver's send routine immediately calls the txeof
  handler (which releases the packets for us anyway).
- In if_ndis.c:ndis_80211_setstate(), implement WEP support.
2003-12-30 21:33:26 +00:00
wpaul
5319092108 Rework resource allocation. Replace the "feel around like a blind man"
method with something a little more intelligent: use BUS_GET_RESOURCE_LIST()
to run through all resources allocated to us and map them as needed. This
way we know exactly what resources need to be mapped and what their RIDs
are without having to guess. This simplifies both ndis_attach() and
ndis_convert_res(), and eliminates the unfriendly "ndisX: couldn't map
<foo>" messages that are sometimes emitted during driver load.
2003-12-29 23:51:59 +00:00
wpaul
57cde0f9a7 Attempt to handle the status field in the ndis_packet oob area correctly.
For received packets, an status of NDIS_STATUS_RESOURCES means we need
to copy the packet data and return the ndis_packet to the driver immediatel.
NDIS_STATUS_SUCCESS means we get to hold onto the packet, but we have
to set the status to NDIS_STATUS_PENDING so the driver knows we're
going to hang onto it for a while.

For transmit packets, NDIS_STATUS_PENDING means the driver will
asynchronously return the packet to us via the ndis_txeof() routine,
and NDIS_STATUS_SUCCESS means the driver sent the frame, and NDIS
(i.e. the OS) retains ownership of the packet and can free it
right away.
2003-12-26 07:01:05 +00:00
wpaul
1bdb22f3a1 Back out the last batch of changes until I have a chance to properly
evaluate them. Whatever they're meant to do, they're doing it wrong.

Also:

- Clean up last bits of NULL fallout in subr_pe
- Don't let ndis_ifmedia_sts() do anything if the IFF_UP flag isn't set
- Implement NdisSystemProcessorCount() and NdisQueryMapRegisterCount().
2003-12-26 03:31:34 +00:00
wpaul
757e456f28 - In ndis_intr(), don't do any interrupt processing if the IFF_UP
flag isn't set.
- In ndis_attach(), halt the NIC before exiting the routine. Calling
  ndis_init() will bring it up again, and we don't want it running
  (and potentially generating interrupts) until we're ready to deal
  with it.
2003-12-25 09:44:49 +00:00
wpaul
41facc2cd6 Avoid using any of the ndis_packet/ndis_packet_private fields for
mbuf<->packet housekeeping. Instead, add a couple of extra fields
to the end of ndis_packet. These should be invisible to the Windows
driver module.

This also lets me get rid of a little bit of evil from ndis_ptom()
(frobbing of the ext_buf field instead of relying on the MEXTADD()
macro).
2003-12-25 06:04:40 +00:00
wpaul
385e9eaf78 - Add stubs for Ndis*File() functions
- Fix ndis_time().
- Implement NdisGetSystemUpTime().
- Implement RtlCopyUnicodeString() and RtlUnicodeStringToAnsiString().
- In ndis_getstate_80211(), use sc->ndis_link to determine connect
  status.

Submitted by:	 Brian Feldman <green@freebsd.org>
2003-12-25 00:40:02 +00:00
wpaul
26d06d7326 - Fix some compiler warnings in subr_pe.c
- Add explicit cardbus attachment in if_ndis.c
- Clean up after moving bus_setup_intr() in ndis_attach().
- When setting an ssid, program an empty ssid as a 1-byte string
  with a single 0 byte. The Microsoft documentation says this is
  how you're supposed to tell the NIC to attach to 'any' ssid.
- Keep trace of callout handles for timers externally from the
  ndis_miniport_timer structs, and run through and clobber them
  all after invoking the haltfunc just in case the driver left one
  running. (We need to make sure all timers are cancelled on driver
  unload.)
- Handle the 'cancelled' argument in ndis_cancel_timer() correctly.
2003-12-24 21:21:18 +00:00
wpaul
3e98c4443b Set up the interrupt earlier in ndis_attach(), because calling the
driver's initfunc may cause an interrupt to be generated. This avoids
the occasional 'stray irqXXX' messages on load.
2003-12-23 18:41:34 +00:00
wpaul
ddbe448dbe Make the NDIS driver depend on the wlan module now that it has
some 802.11 support.
2003-12-23 16:47:01 +00:00
wpaul
a0d9582fee Re-do the handling of ndis_buffers. The NDIS_BUFFER structure is
supposed to be opaque to the driver, however it is exposed through
several macros which expect certain behavior. In my original
implementation, I used the mappedsystemva member of the structure
to hold a pointer to the buffer and bytecount to hold the length.
It turns out you must use the startva pointer to point to the
page containing the start of the buffer and set byteoffset to
the offset within the page where the buffer starts. So, for a buffer
with address 'baseva,' startva is baseva & ~(PAGE_SIZE -1) and
byteoffset is baseva & (PAGE_SIZE -1). We have to maintain this
convention everywhere that ndis_buffers are used.

Fortunately, Microsoft defines some macros for initializing and
manipulating NDIS_BUFFER structures in ntddk.h. I adapted some
of them for use here and used them where appropriate.

This fixes the discrepancy I observed between how RX'ed packet sizes
were being reported in the Broadcom wireless driver and the sample
ethernet drivers that I've tested. This should also help the
Intel Centrino wireless driver work.

Also try to properly initialize the 802.11 BSS and IBSS channels.
(Sadly, the channel value is meaningless since there's no way
in the existing NDIS API to get/set the channel, but this should
take care of any 'invalid channel (NULL)' messages printed on
the console.
2003-12-23 04:08:22 +00:00
wpaul
254fcf7ea1 Big round of updates:
- Make ndis_get_info()/ndis_set_info() sleep on the setdone/getdone
  routines if they get back NDIS_STATUS_PENDING.

- Add a bunch of net80211 support so that 802.11 cards can be twiddled
  with ifconfig. This still needs more work and is not guaranteed to
  work for everyone. It works on my 802.11b/g card anyway.

The problem here is Microsoft doesn't provide a good way to a) learn
all the rates that a card supports (if it has more than 8, you're
kinda hosed) and b) doesn't provide a good way to distinguish between
802.11b, 802.11b/g an 802.11a/b/g cards, so you sort of have to guess.

Setting the SSID and switching between infrastructure/adhoc modes
should work. WEP still needs to be implemented. I can't find any API
for getting/setting the channel other than the registry/sysctl keys.
2003-12-21 00:00:08 +00:00
wpaul
3d5502246f Fix wildcard subsystem case in ndis_probe(). 2003-12-18 04:02:27 +00:00
wpaul
74b1363ea9 Deal with the duplicate sysctl leaf problem. A .inf file may contain
definitions for more than one device (usually differentiated by
the PCI subvendor/subdevice ID). Each device also has its own tree
of registry keys. In some cases, each device has the same keys, but
sometimes each device has a unique tree but with overlap. Originally,
I just had ndiscvt(8) dump out all the keys it could find, and we
would try to apply them to every device we could find. Now, each key
has an index number that matches it to a device in the device ID list.
This lets us create just the keys that apply to a particular device.

I also added an extra field to the device list to hold the subvendor
and subdevice ID.

Some devices are generic, i.e. there is no subsystem definition. If
we have a device that doesn't match a specific subsystem value and
we have a generic entry, we use the generic entry.
2003-12-18 03:51:21 +00:00
wpaul
27d0a79cf6 Silence irritating watchdog timeout messages: if we call
ndis_send_packets() but there's no link yet, we get an immediate
callback to ndis_txeof(), which clears if_timer. But ndis_start()
sets if_timer right after the call to ndis_send_packets(). Set
if_timer before calling ndis_send_packets().

Also fix mutex locking to prevent ndis_txeof() from running in
the middle of ndis_start().
2003-12-14 22:47:01 +00:00
wpaul
953349a8b8 Rework mbuf<->ndis_packet/ndis_packet<->mbuf translation a little to
make it more robust. This should fix problems with crashes under
heavy traffic loads that have been reported. Also add a 'query done'
callback handler to satisfy the e100bex.sys sample Intel driver.
2003-12-14 21:31:32 +00:00
wpaul
7e1ac58149 Commit the first cut of Project Evil, also known as the NDISulator.
Yes, it's what you think it is. Yes, you should run away now.

This is a special compatibility module for allowing Windows NDIS
miniport network drivers to be used with FreeBSD/x86. This provides
_binary_ NDIS compatibility (not source): you can run NDIS driver
code, but you can't build it. There are three main parts:

sys/compat/ndis: the NDIS compat API, which provides binary
compatibility functions for many routines in NDIS.SYS, HAL.dll
and ntoskrnl.exe in Windows (these are the three modules that
most NDIS miniport drivers use). The compat module also contains
a small PE relocator/dynalinker which relocates the Windows .SYS
image and then patches in our native routines.

sys/dev/if_ndis: the if_ndis driver wrapper. This module makes
use of the ndis compat API and can be compiled with a specially
prepared binary image file (ndis_driver_data.h) containing the
Windows .SYS image and registry key information parsed out of the
accompanying .INF file. Once if_ndis.ko is built, it can be loaded
and unloaded just like a native FreeBSD kenrel module.

usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf
into an ndis_driver_data.h file that can be compiled into if_ndis.o.
Contains an .inf file parser graciously provided by Matt Dodd (and
mercilessly hacked upon by me) that strips out device ID info and
registry key info from a .INF file and packages it up with a binary
image array. The ndiscvt(8) utility also does some manipulation of
the segments within the .sys file to make life easier for the kernel
loader. (Doing the manipulation here saves the kernel code from having
to move things around later, which would waste memory.)

ndiscvt is only built for the i386 arch. Only files.i386 has been
updated, and none of this is turned on in GENERIC. It should probably
work on pc98. I have no idea about amd64 or ia64 at this point.

This is still a work in progress. I estimate it's about %85 done, but
I want it under CVS control so I can track subsequent changes. It has
been tested with exactly three drivers: the LinkSys LNE100TX v4 driver
(Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK
(e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It
still needs to have a net80211 stuff added to it. To use it, you would
do something like this:

# cd /sys/modules/ndis
# make; make load
# cd /sys/modules/if_ndis
# ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h
# make; make load
# sysctl -a | grep ndis

All registry keys are mapped to sysctl nodes. Sometimes drivers refer
to registry keys that aren't mentioned in foo.inf. If this happens,
the NDIS API module creates sysctl nodes for these keys on the fly so
you can tweak them.

An example usage of the Broadcom wireless driver would be:

# sysctl hw.ndis0.EnableAutoConnect=1
# sysctl hw.ndis0.SSID="MY_SSID"
# sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc)
# ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up

Things to be done:

- get rid of debug messages
- add in ndis80211 support
- defer transmissions until after a status update with
  NDIS_STATUS_CONNECTED occurs
- Create smarter lookaside list support
- Split off if_ndis_pci.c and if_ndis_pccard.c attachments
- Make sure PCMCIA support works
- Fix ndiscvt to properly parse PCMCIA device IDs from INF files
- write ndisapi.9 man page
2003-12-11 22:34:37 +00:00