| .. | .. | 
|---|
|  | 1 | +// SPDX-License-Identifier: GPL-2.0-or-later | 
|---|
| 1 | 2 | /* | 
|---|
| 2 | 3 | * Linux network device link state notification | 
|---|
| 3 | 4 | * | 
|---|
| 4 | 5 | * Author: | 
|---|
| 5 | 6 | *     Stefan Rompf <sux@loplof.de> | 
|---|
| 6 |  | - * | 
|---|
| 7 |  | - * This program is free software; you can redistribute it and/or | 
|---|
| 8 |  | - * modify it under the terms of the GNU General Public License | 
|---|
| 9 |  | - * as published by the Free Software Foundation; either version | 
|---|
| 10 |  | - * 2 of the License, or (at your option) any later version. | 
|---|
| 11 |  | - * | 
|---|
| 12 | 7 | */ | 
|---|
| 13 | 8 |  | 
|---|
| 14 | 9 | #include <linux/module.h> | 
|---|
| .. | .. | 
|---|
| 39 | 34 |  | 
|---|
| 40 | 35 | static unsigned char default_operstate(const struct net_device *dev) | 
|---|
| 41 | 36 | { | 
|---|
|  | 37 | +	if (netif_testing(dev)) | 
|---|
|  | 38 | +		return IF_OPER_TESTING; | 
|---|
|  | 39 | + | 
|---|
| 42 | 40 | if (!netif_carrier_ok(dev)) | 
|---|
| 43 | 41 | return (dev->ifindex != dev_get_iflink(dev) ? | 
|---|
| 44 | 42 | IF_OPER_LOWERLAYERDOWN : IF_OPER_DOWN); | 
|---|
| .. | .. | 
|---|
| 60 | 58 | write_lock_bh(&dev_base_lock); | 
|---|
| 61 | 59 |  | 
|---|
| 62 | 60 | switch(dev->link_mode) { | 
|---|
|  | 61 | +	case IF_LINK_MODE_TESTING: | 
|---|
|  | 62 | +		if (operstate == IF_OPER_UP) | 
|---|
|  | 63 | +			operstate = IF_OPER_TESTING; | 
|---|
|  | 64 | +		break; | 
|---|
|  | 65 | + | 
|---|
| 63 | 66 | case IF_LINK_MODE_DORMANT: | 
|---|
| 64 | 67 | if (operstate == IF_OPER_UP) | 
|---|
| 65 | 68 | operstate = IF_OPER_DORMANT; | 
|---|
| 66 | 69 | break; | 
|---|
| 67 |  | - | 
|---|
| 68 | 70 | case IF_LINK_MODE_DEFAULT: | 
|---|
| 69 | 71 | default: | 
|---|
| 70 | 72 | break; | 
|---|
| .. | .. | 
|---|
| 79 | 81 | void linkwatch_init_dev(struct net_device *dev) | 
|---|
| 80 | 82 | { | 
|---|
| 81 | 83 | /* Handle pre-registration link state changes */ | 
|---|
| 82 |  | -	if (!netif_carrier_ok(dev) || netif_dormant(dev)) | 
|---|
|  | 84 | +	if (!netif_carrier_ok(dev) || netif_dormant(dev) || | 
|---|
|  | 85 | +	    netif_testing(dev)) | 
|---|
| 83 | 86 | rfc2863_policy(dev); | 
|---|
| 84 | 87 | } | 
|---|
| 85 | 88 |  | 
|---|
| .. | .. | 
|---|
| 168 | 171 |  | 
|---|
| 169 | 172 | static void __linkwatch_run_queue(int urgent_only) | 
|---|
| 170 | 173 | { | 
|---|
|  | 174 | +#define MAX_DO_DEV_PER_LOOP	100 | 
|---|
|  | 175 | + | 
|---|
|  | 176 | +	int do_dev = MAX_DO_DEV_PER_LOOP; | 
|---|
| 171 | 177 | struct net_device *dev; | 
|---|
| 172 | 178 | LIST_HEAD(wrk); | 
|---|
|  | 179 | + | 
|---|
|  | 180 | +	/* Give urgent case more budget */ | 
|---|
|  | 181 | +	if (urgent_only) | 
|---|
|  | 182 | +		do_dev += MAX_DO_DEV_PER_LOOP; | 
|---|
| 173 | 183 |  | 
|---|
| 174 | 184 | /* | 
|---|
| 175 | 185 | * Limit the number of linkwatch events to one | 
|---|
| .. | .. | 
|---|
| 189 | 199 | spin_lock_irq(&lweventlist_lock); | 
|---|
| 190 | 200 | list_splice_init(&lweventlist, &wrk); | 
|---|
| 191 | 201 |  | 
|---|
| 192 |  | -	while (!list_empty(&wrk)) { | 
|---|
|  | 202 | +	while (!list_empty(&wrk) && do_dev > 0) { | 
|---|
| 193 | 203 |  | 
|---|
| 194 | 204 | dev = list_first_entry(&wrk, struct net_device, link_watch_list); | 
|---|
| 195 | 205 | list_del_init(&dev->link_watch_list); | 
|---|
| 196 | 206 |  | 
|---|
| 197 |  | -		if (urgent_only && !linkwatch_urgent_event(dev)) { | 
|---|
|  | 207 | +		if (!netif_device_present(dev) || | 
|---|
|  | 208 | +		    (urgent_only && !linkwatch_urgent_event(dev))) { | 
|---|
| 198 | 209 | list_add_tail(&dev->link_watch_list, &lweventlist); | 
|---|
| 199 | 210 | continue; | 
|---|
| 200 | 211 | } | 
|---|
| 201 | 212 | spin_unlock_irq(&lweventlist_lock); | 
|---|
| 202 | 213 | linkwatch_do_dev(dev); | 
|---|
|  | 214 | +		do_dev--; | 
|---|
| 203 | 215 | spin_lock_irq(&lweventlist_lock); | 
|---|
| 204 | 216 | } | 
|---|
| 205 | 217 |  | 
|---|
|  | 218 | +	/* Add the remaining work back to lweventlist */ | 
|---|
|  | 219 | +	list_splice_init(&wrk, &lweventlist); | 
|---|
|  | 220 | + | 
|---|
| 206 | 221 | if (!list_empty(&lweventlist)) | 
|---|
| 207 | 222 | linkwatch_schedule_work(0); | 
|---|
| 208 | 223 | spin_unlock_irq(&lweventlist_lock); | 
|---|