Skip to content

Commit 4789a21

Browse files
julianwiedmanndavem330
authored andcommitted
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 21b1702 ("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: bcacfcb ("s390/qeth: fix MAC address update sequence") Signed-off-by: Julian Wiedmann <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 4664610 commit 4789a21

File tree

1 file changed

+11
-4
lines changed

1 file changed

+11
-4
lines changed

drivers/s390/net/qeth_l2_main.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -501,27 +501,34 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
501501
return -ERESTARTSYS;
502502
}
503503

504+
/* avoid racing against concurrent state change: */
505+
if (!mutex_trylock(&card->conf_mutex))
506+
return -EAGAIN;
507+
504508
if (!qeth_card_hw_is_reachable(card)) {
505509
ether_addr_copy(dev->dev_addr, addr->sa_data);
506-
return 0;
510+
goto out_unlock;
507511
}
508512

509513
/* don't register the same address twice */
510514
if (ether_addr_equal_64bits(dev->dev_addr, addr->sa_data) &&
511515
(card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))
512-
return 0;
516+
goto out_unlock;
513517

514518
/* add the new address, switch over, drop the old */
515519
rc = qeth_l2_send_setmac(card, addr->sa_data);
516520
if (rc)
517-
return rc;
521+
goto out_unlock;
518522
ether_addr_copy(old_addr, dev->dev_addr);
519523
ether_addr_copy(dev->dev_addr, addr->sa_data);
520524

521525
if (card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED)
522526
qeth_l2_remove_mac(card, old_addr);
523527
card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
524-
return 0;
528+
529+
out_unlock:
530+
mutex_unlock(&card->conf_mutex);
531+
return rc;
525532
}
526533

527534
static void qeth_promisc_to_bridge(struct qeth_card *card)

0 commit comments

Comments
 (0)