Validate the mac address during set
Allow the mac to be set if one of the condition is true.
1) Incoming Mac is of local admin type.
or
2) Incoming mac is same as eeprom Mac.
Fixes openbmc/openbmc#622
Change-Id: I4289b18b8460d56cf9956b7c3028da6468f27974
Signed-off-by: Ratan Gupta <ratagupt@in.ibm.com>
diff --git a/conf/network-manager.conf b/conf/network-manager.conf
new file mode 100644
index 0000000..2f85cec
--- /dev/null
+++ b/conf/network-manager.conf
@@ -0,0 +1,5 @@
+[mac_loc]
+path=/org/openbmc/inventory/system/chassis/io_board
+bus=org.openbmc.Inventory
+interface=org.openbmc.InventoryItem
+property=Custom Field 2
diff --git a/netman.py b/netman.py
index 0af03e7..99984d0 100755
--- a/netman.py
+++ b/netman.py
@@ -17,6 +17,9 @@
from ConfigParser import SafeConfigParser
import glob
+#MAC address mask for locally administered.
+MAC_LOCAL_ADMIN_MASK = 0x20000000000
+BROADCAST_MAC = 0xFFFFFFFFFFFF
DBUS_NAME = 'org.openbmc.NetworkManager'
OBJ_NAME = '/org/openbmc/NetworkManager/Interface'
@@ -73,6 +76,45 @@
rc = call(["systemctl", "try-restart", "systemd-timesyncd.service"])
return rc
+
+def read_mac_provider_info():
+ conf_file = os.path.join('/etc', 'network-manager.conf')
+ if not os.path.exists(conf_file):
+ raise IOError("Could not find %s" % conf_file)
+
+ parser = SafeConfigParser()
+ parser.optionxform = str
+ parser.read(conf_file)
+ sections = parser.sections()
+
+ path = parser.get('mac_loc', 'path')
+ if not path:
+ raise ValueError("Empty path")
+
+ bus_name = parser.get('mac_loc', 'bus')
+ if not bus_name:
+ raise ValueError("Empty bus-name")
+
+ intf = parser.get('mac_loc', 'interface')
+ if not intf:
+ raise ValueError("Empty intf-name")
+
+ prop = parser.get('mac_loc', 'property')
+ if not prop:
+ raise ValueError("Empty prop-name")
+
+ return bus_name, path, intf, prop
+
+
+# Get Mac address from the eeprom
+def get_mac_from_eeprom():
+ bus = dbus.SystemBus()
+ bus_name, path, intf, prop = read_mac_provider_info()
+ obj = bus.get_object(bus_name, path)
+ dbus_method = obj.get_dbus_method("Get", dbus.PROPERTIES_IFACE)
+ return dbus_method(intf, prop)
+
+
class IfAddr ():
def __init__ (self, family, scope, flags, prefixlen, addr, gw):
self.family = family
@@ -110,10 +152,22 @@
if y > 255: return False
return mask.count('.') == 3
- def _isvalidmac(self, mac):
+ def validatemac(self, mac):
macre = '([a-fA-F0-9]{2}[:|\-]?){6}'
- if re.compile(macre).search(mac) : return True
- else: return False
+ if re.compile(macre).search(mac) is None:
+ raise ValueError("Malformed MAC address")
+
+ # Don't allow Broadcast or global unique mac
+ int_mac = int(mac.replace(":", ""), 16)
+ if not (int_mac ^ BROADCAST_MAC):
+ raise ValueError("Given Mac is BroadCast Mac Address")
+
+ if not int_mac & MAC_LOCAL_ADMIN_MASK:
+ int_eep_mac = int(get_mac_from_eeprom(), 16)
+ if int_eep_mac != int_mac:
+ raise ValueError("Given MAC address is neither a local Admin type \
+ nor is same as in eeprom")
+
def _isvalidipv4(self, ipstr, netmask):
ip_parts = ipstr.split(".")
@@ -334,7 +388,8 @@
def SetHwAddress (self, device, mac):
if not self._isvaliddev (device) : raise ValueError, "Invalid Device"
if not self._ishwdev (device) : raise ValueError, "Not a Hardware Device"
- if not self._isvalidmac (mac) : raise ValueError, "Malformed MAC address"
+
+ self.validatemac(mac)
rc = subprocess.call(["fw_setenv", "ethaddr", mac])