[Midnightbsd-cvs] src: if_ndis.c: This fix was found in freebsd pr 124225 Description:
laffer1 at midnightbsd.org
laffer1 at midnightbsd.org
Tue Jan 20 14:53:11 EST 2009
Log Message:
-----------
This fix was found in freebsd pr 124225
Description:
Normally, when packets are queued to the ndis network interface, ndis_start()
is called to move packets from the interface send queue to the underlying
NDIS driver.
If the network link is down or the underlying driver is busy transmitting data,
ndis_start() just returns.
When the link goes up, ndis_starttask() is supposed to be called after
ndis_ticktask() in order to transmit already queued packets.
After a watchdog timeout, ndis_starttask() is likewise supposed to be called
after ndis_resettask().
Unfortunately, work items used for triggering calls to ndis_ticktask(),
ndis_starttask() and ndis_resettask() are placed on separarate task lists which
are handled by separate kernel processes, thus losing ordering information
about when the tasks should be performed in relation to each other.
If the interface send queue is full after a watchdog timeout or link up event
and the tasks were handled in the wrong order then further attempts to send
packets via the interface results in ENOBUFS ("No buffer space available").
How-To-Repeat:
Use the ndis driver for a wireless network card in an area with many APs on
nearby channels and on a machine with many active tcp connections, causing link
to temporarily go down every few hours, and the interface send queue to be
filled while the link is temporarily down.
Fix:
A proper fix is to ensure that related tasks are handled in the correct order.
The following kludge justs add extra attempts at scheduling calls to
ndis_starttask() as part of the processing of ndis_ticktask() and
ndis_resettask(). It depends on defensive coding in IoQueueWorkItem(),
i.e. that nothing is done if the work item is already queued.
Modified Files:
--------------
src/sys/dev/if_ndis:
if_ndis.c (r1.6 -> r1.7)
-------------- next part --------------
Index: if_ndis.c
===================================================================
RCS file: /home/cvs/src/sys/dev/if_ndis/if_ndis.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -L sys/dev/if_ndis/if_ndis.c -L sys/dev/if_ndis/if_ndis.c -u -r1.6 -r1.7
--- sys/dev/if_ndis/if_ndis.c
+++ sys/dev/if_ndis/if_ndis.c
@@ -1564,6 +1564,7 @@
IoQueueWorkItem(sc->ndis_tickitem,
(io_workitem_func)ndis_ticktask_wrap,
WORKQUEUE_CRITICAL, sc);
+ /* XXX: startitem might be handled before tickitem */
IoQueueWorkItem(sc->ndis_startitem,
(io_workitem_func)ndis_starttask_wrap,
WORKQUEUE_CRITICAL, ifp);
@@ -1647,6 +1648,11 @@
ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
}
NDIS_LOCK(sc);
+ /* XXX: Start kludge */
+ IoQueueWorkItem(sc->ndis_startitem,
+ (io_workitem_func)ndis_starttask_wrap,
+ WORKQUEUE_CRITICAL, sc->ifp);
+ /* XXX: End kludge */
#ifdef LINK_STATE_UP
if_link_state_change(sc->ifp, LINK_STATE_UP);
#else
@@ -3146,6 +3152,11 @@
sc = arg;
ndis_reset_nic(sc);
+ /* XXX: Start kludge */
+ IoQueueWorkItem(sc->ndis_startitem,
+ (io_workitem_func)ndis_starttask_wrap,
+ WORKQUEUE_CRITICAL, sc->ifp);
+ /* XXX: End kludge */
return;
}
@@ -3165,6 +3176,7 @@
IoQueueWorkItem(sc->ndis_resetitem,
(io_workitem_func)ndis_resettask_wrap,
WORKQUEUE_CRITICAL, sc);
+ /* XXX: startitem might be handled before resetitem */
IoQueueWorkItem(sc->ndis_startitem,
(io_workitem_func)ndis_starttask_wrap,
WORKQUEUE_CRITICAL, ifp);
More information about the Midnightbsd-cvs
mailing list