aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/net/qeth_l2_main.c
diff options
context:
space:
mode:
authorJulian Wiedmann <jwi@linux.ibm.com>2018-06-29 13:45:51 -0400
committerDavid S. Miller <davem@davemloft.net>2018-06-30 08:19:48 -0400
commit4789a21880488048105590049fc41a99f53d565d (patch)
tree28a075539a81f63fd8ead48dd743abb10c9840de /drivers/s390/net/qeth_l2_main.c
parent4664610537d398d55be19432f9cd9c29c831e159 (diff)
s390/qeth: fix race when setting MAC address
When qeth_l2_set_mac_address() finds the card in a non-reachable state, it merely copies the new MAC address into dev->dev_addr so that __qeth_l2_set_online() can later register it with the HW. But __qeth_l2_set_online() may very well be running concurrently, so we can't trust the card state without appropriate locking: If the online sequence is past the point where it registers dev->dev_addr (but not yet in SOFTSETUP state), any address change needs to be properly programmed into the HW. Otherwise the netdevice ends up with a different MAC address than what's set in the HW, and inbound traffic is not forwarded as expected. This is most likely to occur for OSD in LPAR, where commit 21b1702af12e ("s390/qeth: improve fallback to random MAC address") now triggers eg. systemd to immediately change the MAC when the netdevice is registered with a NET_ADDR_RANDOM address. Fixes: bcacfcbc82b4 ("s390/qeth: fix MAC address update sequence") Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/s390/net/qeth_l2_main.c')
-rw-r--r--drivers/s390/net/qeth_l2_main.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index a7cb37da6a21..7daf125dae76 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -501,27 +501,34 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
501 return -ERESTARTSYS; 501 return -ERESTARTSYS;
502 } 502 }
503 503
504 /* avoid racing against concurrent state change: */
505 if (!mutex_trylock(&card->conf_mutex))
506 return -EAGAIN;
507
504 if (!qeth_card_hw_is_reachable(card)) { 508 if (!qeth_card_hw_is_reachable(card)) {
505 ether_addr_copy(dev->dev_addr, addr->sa_data); 509 ether_addr_copy(dev->dev_addr, addr->sa_data);
506 return 0; 510 goto out_unlock;
507 } 511 }
508 512
509 /* don't register the same address twice */ 513 /* don't register the same address twice */
510 if (ether_addr_equal_64bits(dev->dev_addr, addr->sa_data) && 514 if (ether_addr_equal_64bits(dev->dev_addr, addr->sa_data) &&
511 (card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED)) 515 (card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))
512 return 0; 516 goto out_unlock;
513 517
514 /* add the new address, switch over, drop the old */ 518 /* add the new address, switch over, drop the old */
515 rc = qeth_l2_send_setmac(card, addr->sa_data); 519 rc = qeth_l2_send_setmac(card, addr->sa_data);
516 if (rc) 520 if (rc)
517 return rc; 521 goto out_unlock;
518 ether_addr_copy(old_addr, dev->dev_addr); 522 ether_addr_copy(old_addr, dev->dev_addr);
519 ether_addr_copy(dev->dev_addr, addr->sa_data); 523 ether_addr_copy(dev->dev_addr, addr->sa_data);
520 524
521 if (card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED) 525 if (card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED)
522 qeth_l2_remove_mac(card, old_addr); 526 qeth_l2_remove_mac(card, old_addr);
523 card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED; 527 card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
524 return 0; 528
529out_unlock:
530 mutex_unlock(&card->conf_mutex);
531 return rc;
525} 532}
526 533
527static void qeth_promisc_to_bridge(struct qeth_card *card) 534static void qeth_promisc_to_bridge(struct qeth_card *card)