- 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.
This commit is contained in:
Bill Paul 2004-03-20 23:39:43 +00:00
parent d7c5555174
commit f6159e042d
6 changed files with 102 additions and 217 deletions

View File

@ -1152,7 +1152,6 @@ ndis_halt_nic(arg)
ndis_handle adapter;
__stdcall ndis_halt_handler haltfunc;
struct ifnet *ifp;
struct ndis_timer_entry *ne;
sc = arg;
ifp = &sc->arpcom.ac_if;
@ -1178,14 +1177,6 @@ ndis_halt_nic(arg)
NDIS_LOCK(sc);
sc->ndis_block.nmb_miniportadapterctx = NULL;
NDIS_UNLOCK(sc);
/* Clobber all the timers in case the driver left one running. */
while (!TAILQ_EMPTY(&sc->ndis_block.nmb_timerlist)) {
ne = TAILQ_FIRST(&sc->ndis_block.nmb_timerlist);
TAILQ_REMOVE(&sc->ndis_block.nmb_timerlist, ne, link);
callout_stop(&ne->nte_ch);
free(ne, M_DEVBUF);
}
return(0);
}

View File

@ -835,7 +835,7 @@ struct ndis_kevent {
};
struct ndis_event {
struct ndis_kevent ne_event;
struct nt_kevent ne_event;
};
typedef struct ndis_event ndis_event;
@ -858,8 +858,8 @@ struct ndis_kdpc {
};
struct ndis_timer {
struct ndis_ktimer nt_timer;
struct ndis_kdpc nt_dpc;
struct ktimer nt_ktimer;
struct kdpc nt_kdpc;
};
typedef struct ndis_timer ndis_timer;
@ -867,10 +867,11 @@ typedef struct ndis_timer ndis_timer;
typedef void (*ndis_timer_function)(void *, void *, void *, void *);
struct ndis_miniport_timer {
struct ndis_ktimer nmt_ktimer;
struct ndis_kdpc nmt_dpc;
struct ktimer nmt_ktimer;
struct kdpc nmt_kdpc;
ndis_timer_function nmt_timerfunc;
void *nmt_timerctx;
ndis_miniport_block *nmt_block;
struct ndis_miniport_timer *nmt_nexttimer;
};

View File

@ -472,7 +472,21 @@ extern struct mtx *ntoskrnl_dispatchlock;
__BEGIN_DECLS
extern int ntoskrnl_libinit(void);
extern int ntoskrnl_libfini(void);
extern void ntoskrnl_wakeup(void *);
__stdcall extern void ntoskrnl_init_dpc(kdpc *, void *, void *);
__stdcall extern void ntoskrnl_init_timer(ktimer *);
__stdcall extern void ntoskrnl_init_timer_ex(ktimer *, uint32_t);
__stdcall extern uint8_t ntoskrnl_set_timer(ktimer *, int64_t, kdpc *);
__stdcall extern uint8_t ntoskrnl_set_timer_ex(ktimer *, int64_t,
uint32_t, kdpc *);
__stdcall extern uint8_t ntoskrnl_cancel_timer(ktimer *);
__stdcall extern uint8_t ntoskrnl_read_timer(ktimer *);
__stdcall uint32_t ntoskrnl_waitforobj(nt_dispatch_header *, uint32_t,
uint32_t, uint8_t, int64_t *);
__stdcall void ntoskrnl_init_event(nt_kevent *, uint32_t, uint8_t);
__stdcall void ntoskrnl_clear_event(nt_kevent *);
__stdcall uint32_t ntoskrnl_read_event(nt_kevent *);
__stdcall uint32_t ntoskrnl_set_event(nt_kevent *, uint32_t, uint8_t);
__stdcall uint32_t ntoskrnl_reset_event(nt_kevent *);
__END_DECLS
#endif /* _NTOSKRNL_VAR_H_ */

View File

@ -148,15 +148,13 @@ static void ndis_map_cb(void *, bus_dma_segment_t *, int, int);
__stdcall static void ndis_vtophys_load(ndis_handle, ndis_buffer *,
uint32_t, uint8_t, ndis_paddr_unit *, uint32_t *);
__stdcall static void ndis_vtophys_unload(ndis_handle, ndis_buffer *, uint32_t);
__stdcall static void ndis_create_timer(ndis_miniport_timer *, ndis_handle *,
__stdcall static void ndis_create_timer(ndis_miniport_timer *, ndis_handle,
ndis_timer_function, void *);
__stdcall static void ndis_init_timer(ndis_timer *,
ndis_timer_function, void *);
static void ndis_timercall(void *);
__stdcall static void ndis_set_timer(ndis_miniport_timer *, uint32_t);
static void ndis_tick(void *);
__stdcall static void ndis_set_timer(ndis_timer *, uint32_t);
__stdcall static void ndis_set_periodic_timer(ndis_miniport_timer *, uint32_t);
__stdcall static void ndis_cancel_timer(ndis_miniport_timer *, uint8_t *);
__stdcall static void ndis_cancel_timer(ndis_timer *, uint8_t *);
__stdcall static void ndis_query_resources(ndis_status *, ndis_handle,
ndis_resource_list *, uint32_t *);
__stdcall static ndis_status ndis_register_ioport(void **,
@ -521,6 +519,7 @@ ndis_encode_parm(block, oid, type, parm)
{
uint16_t *unicode;
ndis_unicode_string *ustr;
int base = 0;
unicode = (uint16_t *)&block->nmb_dummybuf;
@ -533,14 +532,22 @@ ndis_encode_parm(block, oid, type, parm)
ustr->nus_buf = unicode;
break;
case ndis_parm_int:
if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0)
base = 16;
else
base = 10;
(*parm)->ncp_type = ndis_parm_int;
(*parm)->ncp_parmdata.ncp_intdata =
strtol((char *)oid->oid_arg1, NULL, 10);
strtol((char *)oid->oid_arg1, NULL, base);
break;
case ndis_parm_hexint:
if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0)
base = 16;
else
base = 10;
(*parm)->ncp_type = ndis_parm_hexint;
(*parm)->ncp_parmdata.ncp_intdata =
strtoul((char *)oid->oid_arg1, NULL, 16);
strtoul((char *)oid->oid_arg1, NULL, base);
break;
default:
return(NDIS_STATUS_FAILURE);
@ -936,30 +943,8 @@ ndis_init_timer(timer, func, ctx)
ndis_timer_function func;
void *ctx;
{
struct ndis_timer_entry *ne = NULL;
ndis_miniport_block *block = NULL;
TAILQ_FOREACH(block, &ndis_devhead, link) {
if (block->nmb_miniportadapterctx == ctx)
break;
}
if (block->nmb_miniportadapterctx != ctx)
panic("NDIS driver timer context didn't "
"match any adapter contexts");
ne = malloc(sizeof(struct ndis_timer_entry), M_DEVBUF, M_NOWAIT);
callout_init(&ne->nte_ch, CALLOUT_MPSAFE);
TAILQ_INSERT_TAIL(&block->nmb_timerlist, ne, link);
ne->nte_timer = (ndis_miniport_timer *)timer;
INIT_LIST_HEAD((&timer->nt_timer.nk_header.dh_waitlisthead));
timer->nt_timer.nk_header.dh_sigstate = FALSE;
timer->nt_timer.nk_header.dh_type = EVENT_TYPE_NOTIFY;
timer->nt_timer.nk_header.dh_size = OTYPE_TIMER;
timer->nt_dpc.nk_sysarg1 = &ne->nte_ch;
timer->nt_dpc.nk_deferedfunc = (ndis_kdpc_func)func;
timer->nt_dpc.nk_deferredctx = ctx;
ntoskrnl_init_timer(&timer->nt_ktimer);
ntoskrnl_init_dpc(&timer->nt_kdpc, func, ctx);
return;
}
@ -967,97 +952,37 @@ ndis_init_timer(timer, func, ctx)
__stdcall static void
ndis_create_timer(timer, handle, func, ctx)
ndis_miniport_timer *timer;
ndis_handle *handle;
ndis_handle handle;
ndis_timer_function func;
void *ctx;
{
struct ndis_timer_entry *ne = NULL;
ndis_miniport_block *block;
block = (ndis_miniport_block *)handle;
/* Save the funcptr and context */
ne = malloc(sizeof(struct ndis_timer_entry), M_DEVBUF, M_NOWAIT);
callout_init(&ne->nte_ch, CALLOUT_MPSAFE);
TAILQ_INSERT_TAIL(&block->nmb_timerlist, ne, link);
ne->nte_timer = timer;
timer->nmt_timerfunc = func;
timer->nmt_timerctx = ctx;
timer->nmt_block = handle;
INIT_LIST_HEAD((&timer->nmt_ktimer.nk_header.dh_waitlisthead));
timer->nmt_ktimer.nk_header.dh_sigstate = FALSE;
timer->nmt_ktimer.nk_header.dh_type = EVENT_TYPE_NOTIFY;
timer->nmt_ktimer.nk_header.dh_size = OTYPE_TIMER;
timer->nmt_dpc.nk_sysarg1 = &ne->nte_ch;
timer->nmt_dpc.nk_deferedfunc = (ndis_kdpc_func)func;
timer->nmt_dpc.nk_deferredctx = ctx;
ntoskrnl_init_timer(&timer->nmt_ktimer);
ntoskrnl_init_dpc(&timer->nmt_kdpc, func, ctx);
return;
}
/*
* The driver's timer callout is __stdcall function, so we need this
* intermediate step.
*/
static void
ndis_timercall(arg)
void *arg;
{
ndis_miniport_timer *timer;
__stdcall ndis_timer_function timerfunc;
timer = arg;
timerfunc = (ndis_timer_function)timer->nmt_dpc.nk_deferedfunc;
timerfunc(NULL, timer->nmt_dpc.nk_deferredctx, NULL, NULL);
ntoskrnl_wakeup(&timer->nmt_ktimer.nk_header);
return;
}
/*
* Windows specifies timeouts in milliseconds. We specify timeouts
* in hz, so some conversion is required.
* In Windows, there's both an NdisMSetTimer() and an NdisSetTimer(),
* but the former is just a macro wrapper around the latter.
*/
__stdcall static void
ndis_set_timer(timer, msecs)
ndis_miniport_timer *timer;
ndis_timer *timer;
uint32_t msecs;
{
struct callout *ch;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = msecs * 1000;
ch = timer->nmt_dpc.nk_sysarg1;
timer->nmt_dpc.nk_sysarg2 = ndis_timercall;
timer->nmt_ktimer.nk_header.dh_sigstate = FALSE;
callout_reset(ch, tvtohz(&tv), timer->nmt_dpc.nk_sysarg2, timer);
return;
}
static void
ndis_tick(arg)
void *arg;
{
ndis_miniport_timer *timer;
struct callout *ch;
__stdcall ndis_timer_function timerfunc;
struct timeval tv;
timer = arg;
/* Automatically reload timer. */
tv.tv_sec = 0;
tv.tv_usec = timer->nmt_ktimer.nk_period * 1000;
ch = timer->nmt_dpc.nk_sysarg1;
timer->nmt_ktimer.nk_header.dh_sigstate = FALSE;
timer->nmt_dpc.nk_sysarg2 = ndis_tick;
callout_reset(ch, tvtohz(&tv), timer->nmt_dpc.nk_sysarg2, timer);
timerfunc = (ndis_timer_function)timer->nmt_dpc.nk_deferedfunc;
timerfunc(NULL, timer->nmt_dpc.nk_deferredctx, NULL, NULL);
ntoskrnl_wakeup(&timer->nmt_ktimer.nk_header);
/*
* KeSetTimer() wants the period in
* hundred nanosecond intervals.
*/
ntoskrnl_set_timer(&timer->nt_ktimer,
((int64_t)msecs * -10000), &timer->nt_kdpc);
return;
}
@ -1067,35 +992,25 @@ ndis_set_periodic_timer(timer, msecs)
ndis_miniport_timer *timer;
uint32_t msecs;
{
struct callout *ch;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = msecs * 1000;
timer->nmt_ktimer.nk_period = msecs;
ch = timer->nmt_dpc.nk_sysarg1;
timer->nmt_dpc.nk_sysarg2 = ndis_tick;
timer->nmt_ktimer.nk_header.dh_sigstate = FALSE;
callout_reset(ch, tvtohz(&tv), timer->nmt_dpc.nk_sysarg2, timer);
ntoskrnl_set_timer_ex(&timer->nmt_ktimer,
((int64_t)msecs * -10000), msecs, &timer->nmt_kdpc);
return;
}
/*
* Technically, this is really NdisCancelTimer(), but we also
* (ab)use it for NdisMCancelTimer(), since in our implementation
* we don't need the extra info in the ndis_miniport_timer
* structure.
*/
__stdcall static void
ndis_cancel_timer(timer, cancelled)
ndis_miniport_timer *timer;
ndis_timer *timer;
uint8_t *cancelled;
{
struct callout *ch;
if (timer == NULL)
return;
ch = timer->nmt_dpc.nk_sysarg1;
if (ch == NULL)
return;
callout_stop(ch);
*cancelled = timer->nmt_ktimer.nk_header.dh_sigstate;
*cancelled = ntoskrnl_cancel_timer(&timer->nt_ktimer);
return;
}
@ -1990,10 +1905,13 @@ __stdcall static void
ndis_init_event(event)
ndis_event *event;
{
event->ne_event.nk_header.dh_sigstate = FALSE;
event->ne_event.nk_header.dh_size = OTYPE_EVENT;
event->ne_event.nk_header.dh_type = EVENT_TYPE_NOTIFY;
INIT_LIST_HEAD((&event->ne_event.nk_header.dh_waitlisthead));
/*
* NDIS events are always synchronization
* events, and should be initialized to the
* not signaled state.
*/
ntoskrnl_init_event(&event->ne_event, EVENT_TYPE_SYNC, FALSE);
return;
}
@ -2001,7 +1919,7 @@ __stdcall static void
ndis_set_event(event)
ndis_event *event;
{
ntoskrnl_wakeup(event);
ntoskrnl_set_event(&event->ne_event, 0, 0);
return;
}
@ -2009,56 +1927,27 @@ __stdcall static void
ndis_reset_event(event)
ndis_event *event;
{
event->ne_event.nk_header.dh_sigstate = FALSE;
ntoskrnl_reset_event(&event->ne_event);
return;
}
/*
* This is a stripped-down version of KeWaitForSingleObject().
* Maybe it ought to just call ntoskrnl_waitforobj() to reduce
* code duplication.
*/
__stdcall static uint8_t
ndis_wait_event(event, msecs)
ndis_event *event;
uint32_t msecs;
{
int error;
struct timeval tv;
wait_block w;
struct thread *td = curthread;
int64_t duetime;
uint32_t rval;
mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock);
duetime = ((int64_t)msecs * -10000);
if (event->ne_event.nk_header.dh_sigstate == TRUE) {
mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
return(TRUE);
}
rval = ntoskrnl_waitforobj((nt_dispatch_header *)event,
0, 0, TRUE, msecs ? &duetime : NULL);
INSERT_LIST_TAIL((&event->ne_event.nk_header.dh_waitlisthead),
(&w.wb_waitlist));
if (rval == STATUS_TIMEOUT)
return(FALSE);
tv.tv_sec = 0;
tv.tv_usec = msecs * 1000;
w.wb_kthread = td;
w.wb_object = &event->ne_event.nk_header;
mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
if (td->td_proc->p_flag & P_KTHREAD)
error = kthread_suspend(td->td_proc, tvtohz(&tv));
else
error = tsleep(td, PPAUSE|PCATCH, "ndiswe", tvtohz(&tv));
mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock);
REMOVE_LIST_ENTRY((&w.wb_waitlist));
mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock);
return(event->ne_event.nk_header.dh_sigstate);
return(TRUE);
}
__stdcall static ndis_status

View File

@ -80,25 +80,11 @@ __stdcall static void *ntoskrnl_iobuildsynchfsdreq(uint32_t, void *,
void *, uint32_t, uint32_t *, void *, void *);
__stdcall static uint32_t ntoskrnl_iofcalldriver(/*void *, void * */ void);
__stdcall static void ntoskrnl_iofcompletereq(/*void *, uint8_t*/ void);
__stdcall static uint32_t ntoskrnl_waitforobj(nt_dispatch_header *, uint32_t,
uint32_t, uint8_t, int64_t *);
__stdcall static uint32_t ntoskrnl_waitforobjs(uint32_t,
nt_dispatch_header **, uint32_t, uint32_t, uint32_t, uint8_t,
int64_t *, wait_block *);
__stdcall static void ntoskrnl_init_event(nt_kevent *, uint32_t, uint8_t);
__stdcall static void ntoskrnl_clear_event(nt_kevent *);
__stdcall static uint32_t ntoskrnl_read_event(nt_kevent *);
__stdcall static uint32_t ntoskrnl_set_event(nt_kevent *, uint32_t, uint8_t);
__stdcall static uint32_t ntoskrnl_reset_event(nt_kevent *);
static void ntoskrnl_wakeup(void *);
static void ntoskrnl_timercall(void *);
__stdcall static void ntoskrnl_init_dpc(kdpc *, void *, void *);
__stdcall static void ntoskrnl_init_timer(ktimer *);
__stdcall static void ntoskrnl_init_timer_ex(ktimer *, uint32_t);
__stdcall static uint8_t ntoskrnl_set_timer(ktimer *, int64_t, kdpc *);
__stdcall static uint8_t ntoskrnl_set_timer_ex(ktimer *, int64_t,
uint32_t, kdpc *);
__stdcall static uint8_t ntoskrnl_cancel_timer(ktimer *);
__stdcall static uint8_t ntoskrnl_read_timer(ktimer *);
__stdcall static void ntoskrnl_writereg_ushort(uint16_t *, uint16_t);
__stdcall static uint16_t ntoskrnl_readreg_ushort(uint16_t *);
__stdcall static void ntoskrnl_writereg_ulong(uint32_t *, uint32_t);
@ -325,7 +311,7 @@ ntoskrnl_iofcompletereq(/*irp, prioboost*/)
return;
}
void
static void
ntoskrnl_wakeup(arg)
void *arg;
{
@ -430,7 +416,7 @@ ntoskrnl_time(tval)
* EINVAL, we need to use tsleep() instead.
*/
__stdcall static uint32_t
__stdcall uint32_t
ntoskrnl_waitforobj(obj, reason, mode, alertable, duetime)
nt_dispatch_header *obj;
uint32_t reason;
@ -1448,7 +1434,7 @@ ntoskrnl_read_mutex(kmutex)
return(kmutex->km_header.dh_sigstate);
}
__stdcall static void
__stdcall void
ntoskrnl_init_event(kevent, type, state)
nt_kevent *kevent;
uint32_t type;
@ -1461,7 +1447,7 @@ ntoskrnl_init_event(kevent, type, state)
return;
}
__stdcall static uint32_t
__stdcall uint32_t
ntoskrnl_reset_event(kevent)
nt_kevent *kevent;
{
@ -1475,7 +1461,7 @@ ntoskrnl_reset_event(kevent)
return(prevstate);
}
__stdcall static uint32_t
__stdcall uint32_t
ntoskrnl_set_event(kevent, increment, kwait)
nt_kevent *kevent;
uint32_t increment;
@ -1489,7 +1475,7 @@ ntoskrnl_set_event(kevent, increment, kwait)
return(prevstate);
}
__stdcall static void
__stdcall void
ntoskrnl_clear_event(kevent)
nt_kevent *kevent;
{
@ -1497,7 +1483,7 @@ ntoskrnl_clear_event(kevent)
return;
}
__stdcall static uint32_t
__stdcall uint32_t
ntoskrnl_read_event(kevent)
nt_kevent *kevent;
{
@ -1669,7 +1655,11 @@ ntoskrnl_timercall(arg)
/*
* If this is a periodic timer, re-arm it
* so it will fire again.
* so it will fire again. We do this before
* calling any deferred procedure calls because
* it's possible the DPC might cancel the timer,
* in which case it would be wrong for us to
* re-arm it again afterwards.
*/
if (timer->k_period) {
@ -1690,7 +1680,7 @@ ntoskrnl_timercall(arg)
return;
}
__stdcall static void
__stdcall void
ntoskrnl_init_timer(timer)
ktimer *timer;
{
@ -1706,7 +1696,7 @@ ntoskrnl_init_timer(timer)
return;
}
__stdcall static void
__stdcall void
ntoskrnl_init_timer_ex(timer, type)
ktimer *timer;
uint32_t type;
@ -1723,7 +1713,7 @@ ntoskrnl_init_timer_ex(timer, type)
return;
}
__stdcall static void
__stdcall void
ntoskrnl_init_dpc(dpc, dpcfunc, dpcctx)
kdpc *dpc;
void *dpcfunc;
@ -1738,7 +1728,7 @@ ntoskrnl_init_dpc(dpc, dpcfunc, dpcctx)
return;
}
__stdcall static uint8_t
__stdcall uint8_t
ntoskrnl_set_timer_ex(timer, duetime, period, dpc)
ktimer *timer;
int64_t duetime;
@ -1784,7 +1774,7 @@ ntoskrnl_set_timer_ex(timer, duetime, period, dpc)
return(pending);
}
__stdcall static uint8_t
__stdcall uint8_t
ntoskrnl_set_timer(timer, duetime, dpc)
ktimer *timer;
int64_t duetime;
@ -1793,7 +1783,7 @@ ntoskrnl_set_timer(timer, duetime, dpc)
return (ntoskrnl_set_timer_ex(timer, duetime, 0, dpc));
}
__stdcall static uint8_t
__stdcall uint8_t
ntoskrnl_cancel_timer(timer)
ktimer *timer;
{
@ -1813,7 +1803,7 @@ ntoskrnl_cancel_timer(timer)
return(pending);
}
__stdcall static uint8_t
__stdcall uint8_t
ntoskrnl_read_timer(timer)
ktimer *timer;
{

View File

@ -1596,7 +1596,7 @@ ndis_setstate_80211(sc)
ic->ic_wep_mode = IEEE80211_WEP_8021X;
}
#endif
arg = NDIS_80211_AUTHMODE_AUTO;
arg = NDIS_80211_AUTHMODE_OPEN;
} else {
arg = NDIS_80211_WEPSTAT_DISABLED;
len = sizeof(arg);