Skip to content

Commit 22604c8

Browse files
marineamdavem330
authored andcommitted
net: Fix for initial link state in 2.6.28
From: Michael Marineau <[email protected]> Commit b473001 "Do not fire linkwatch events until the device is registered." was made as a workaround for drivers that call netif_carrier_off before registering the device. Unfortunately this causes these drivers to incorrectly report their link status as IF_OPER_UNKNOWN which can falsely set the IFF_RUNNING flag when the interface is first brought up. This issues was previously pointed out[1] but was dismissed saying that IFF_RUNNING is not related to the link status. From my digging IFF_RUNNING, as reported to userspace, is based on the link state. It is set based on __LINK_STATE_START and IF_OPER_UP or IF_OPER_UNKNOWN. See [2], [3], and [4]. (Whether or not the kernel has IFF_RUNNING set in flags is not reported to user space so it may well be independent of the link, I don't know if and when it may get set.) The end result depends slightly depending on the driver. The the two I tested were e1000e and b44. With e1000e if the system is booted without a network cable attached the interface will falsely report RUNNING when it is brought up causing NetworkManager to attempt to start it and eventually time out. With b44 when the system is booted with a network cable attached and brought up with dhcpcd it will time out the first time. The attached patch that will still set the operstate variable correctly to IF_OPER_UP/DOWN/etc when linkwatch_fire_event is called but then return rather than skipping the linkwatch_fire_event call entirely as the previous fix did. (sorry it isn't inline, I don't have a patch friendly email client at the moment) Signed-off-by: David S. Miller <[email protected]>
1 parent 745417e commit 22604c8

File tree

2 files changed

+6
-5
lines changed

2 files changed

+6
-5
lines changed

net/core/link_watch.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,6 @@ static void __linkwatch_run_queue(int urgent_only)
178178
*/
179179
clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state);
180180

181-
rfc2863_policy(dev);
182181
if (dev->flags & IFF_UP) {
183182
if (netif_carrier_ok(dev))
184183
dev_activate(dev);
@@ -215,6 +214,12 @@ void linkwatch_fire_event(struct net_device *dev)
215214
{
216215
bool urgent = linkwatch_urgent_event(dev);
217216

217+
rfc2863_policy(dev);
218+
219+
/* Some drivers call netif_carrier_off early */
220+
if (dev->reg_state == NETREG_UNINITIALIZED)
221+
return;
222+
218223
if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) {
219224
dev_hold(dev);
220225

net/sched/sch_generic.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,6 @@ static void dev_watchdog_down(struct net_device *dev)
270270
void netif_carrier_on(struct net_device *dev)
271271
{
272272
if (test_and_clear_bit(__LINK_STATE_NOCARRIER, &dev->state)) {
273-
if (dev->reg_state == NETREG_UNINITIALIZED)
274-
return;
275273
linkwatch_fire_event(dev);
276274
if (netif_running(dev))
277275
__netdev_watchdog_up(dev);
@@ -288,8 +286,6 @@ EXPORT_SYMBOL(netif_carrier_on);
288286
void netif_carrier_off(struct net_device *dev)
289287
{
290288
if (!test_and_set_bit(__LINK_STATE_NOCARRIER, &dev->state)) {
291-
if (dev->reg_state == NETREG_UNINITIALIZED)
292-
return;
293289
linkwatch_fire_event(dev);
294290
}
295291
}

0 commit comments

Comments
 (0)