aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@gmail.com>2013-01-20 20:17:22 -0500
committerDavid S. Miller <davem@davemloft.net>2013-01-21 14:07:44 -0500
commitfa0879e37b59e8e3f130a30a9e6fa515717c5bdd (patch)
tree04a7a3b6464b582a86d8193692a1588bf7049e53
parent40cbfc37075a2ae2ed6c769cb0e9193819511f0a (diff)
net: split eth_mac_addr for better error handling
When we set mac address, software mac address in system and hardware mac address all need to be updated. Current eth_mac_addr() doesn't allow callers to implement error handling nicely. This patch split eth_mac_addr() to prepare part and real commit part, then we can prepare first, and try to change hardware address, then do the real commit if hardware address is set successfully. Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com> Signed-off-by: Amos Kong <akong@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/etherdevice.h2
-rw-r--r--net/ethernet/eth.c41
2 files changed, 37 insertions, 6 deletions
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index 1a43e1b4f7ad..c623861964e4 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -40,6 +40,8 @@ extern int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh,
40extern void eth_header_cache_update(struct hh_cache *hh, 40extern void eth_header_cache_update(struct hh_cache *hh,
41 const struct net_device *dev, 41 const struct net_device *dev,
42 const unsigned char *haddr); 42 const unsigned char *haddr);
43extern int eth_prepare_mac_addr_change(struct net_device *dev, void *p);
44extern void eth_commit_mac_addr_change(struct net_device *dev, void *p);
43extern int eth_mac_addr(struct net_device *dev, void *p); 45extern int eth_mac_addr(struct net_device *dev, void *p);
44extern int eth_change_mtu(struct net_device *dev, int new_mtu); 46extern int eth_change_mtu(struct net_device *dev, int new_mtu);
45extern int eth_validate_addr(struct net_device *dev); 47extern int eth_validate_addr(struct net_device *dev);
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index bc39c8c8f589..a36c85eab5b4 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -272,6 +272,36 @@ void eth_header_cache_update(struct hh_cache *hh,
272EXPORT_SYMBOL(eth_header_cache_update); 272EXPORT_SYMBOL(eth_header_cache_update);
273 273
274/** 274/**
275 * eth_prepare_mac_addr_change - prepare for mac change
276 * @dev: network device
277 * @p: socket address
278 */
279int eth_prepare_mac_addr_change(struct net_device *dev, void *p)
280{
281 struct sockaddr *addr = p;
282
283 if (!(dev->priv_flags & IFF_LIVE_ADDR_CHANGE) && netif_running(dev))
284 return -EBUSY;
285 if (!is_valid_ether_addr(addr->sa_data))
286 return -EADDRNOTAVAIL;
287 return 0;
288}
289EXPORT_SYMBOL(eth_prepare_mac_addr_change);
290
291/**
292 * eth_commit_mac_addr_change - commit mac change
293 * @dev: network device
294 * @p: socket address
295 */
296void eth_commit_mac_addr_change(struct net_device *dev, void *p)
297{
298 struct sockaddr *addr = p;
299
300 memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
301}
302EXPORT_SYMBOL(eth_commit_mac_addr_change);
303
304/**
275 * eth_mac_addr - set new Ethernet hardware address 305 * eth_mac_addr - set new Ethernet hardware address
276 * @dev: network device 306 * @dev: network device
277 * @p: socket address 307 * @p: socket address
@@ -283,13 +313,12 @@ EXPORT_SYMBOL(eth_header_cache_update);
283 */ 313 */
284int eth_mac_addr(struct net_device *dev, void *p) 314int eth_mac_addr(struct net_device *dev, void *p)
285{ 315{
286 struct sockaddr *addr = p; 316 int ret;
287 317
288 if (!(dev->priv_flags & IFF_LIVE_ADDR_CHANGE) && netif_running(dev)) 318 ret = eth_prepare_mac_addr_change(dev, p);
289 return -EBUSY; 319 if (ret < 0)
290 if (!is_valid_ether_addr(addr->sa_data)) 320 return ret;
291 return -EADDRNOTAVAIL; 321 eth_commit_mac_addr_change(dev, p);
292 memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
293 return 0; 322 return 0;
294} 323}
295EXPORT_SYMBOL(eth_mac_addr); 324EXPORT_SYMBOL(eth_mac_addr);