Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Fixed UniFi AP hardware type and firmware version retrieval #8005
Just a small change here - the existing code to pull hardware/version details from UniFi APs uses a part of IEEE802dot11-MIB which the UniFi APs are... somewhat confused about how to respond to.
Short version; instead of pulling dot11manufacturerName and dot11manufacturerProductVersion from IEEE802dot11-MIB, we pull unifiApSystemModel.0 and unifiApSystemVersion.0 from UBNT-UniFi-MIB. I've also dropped the nobulk flag from the OS definition as it's redundant.
In the existing code, we iterate through several possible entity IDs in an attempt to find a valid dot11manufacturerName.x and dot11manufacturerProductVersion.x in IEEE802dot11-MIB. These entities are indexed by vAP interface (SSID/vwire) - in my installation I've seen the index as high as 27 as it increments on config change;
There's also an issue with the dot11manufacturerProductVersion OID - Ubiquiti released a major UAP firmware upgrade (3.9.15) a few weeks ago; amongst other things, it replaces tinysnmpd with Net-SNMP & brings v2c/v3 support. Devices on the newer firmware don't respond to dot11manufacturerProductVersion at all; a getnext for the OID skips down the tree to sysDescr.0 without returning any entities.
Between these two things, model and version detection are broken for UAPs on this firmware and several beta versions. Fortunately, UBNT-UniFi-MIB provides the answer; this MIB is supported by both old and new SNMP daemons, hasn't changed in quite a while, and gives us unifiApSystemModel.0 + unifiApSystemVersion.0. So we just pull those instead, and call it a day.
While we're at it, I've dropped the nobulk flag from the OS. This doesn't break compatibility with older firmwares; the ubiquiti tinysnmpd implementation only supported SNMPv1, which doesn't do bulkwalks, and snmp.inc.php disables bulkwalks for v1 devices too just for good measure;
And the change has the desired effect;
Shiny. Works just fine on firmwares as far back as 3.7.37, too.
DO NOT DELETE THIS TEXT
Pre-commit says I'm fine! yay.
If you would like to test this pull request then please run:
I've tested on all of the Gen2 802.11ac hardware except UAP-AC-LR, so that's UAP-AC-Pro, UAP-AC-Lite, UAP-AC-M, UAP-AC-M-Pro - as well as UAP-AC-HD, which is Gen3.
All hardware tested was on firmware 3.9.18, though I also tested on a UAP-AC-Pro running firmware 3.7.37.
I don't have access to any older devices/firmwares to test; this MIB was officially released mid-2016, and hasn't changed much (if any) since release. For earlier firmwares such as v3.2.7 from circa 2014, there are snmpwalk outputs posted on the UBNT forums;
This actually matches up with the earlier OIDs used - dot11manufacturerProductName and dot11manufacturerProductVersion, but is available at the .0 entity as well as the entities indexed by vAP (unlike the newer firmware). The version here also returns the full firmware ID, so the regex from the original file would need to come back if we want a clean version number.
It looks like the original code here would have worked fine with the older configuration & was modified to check higher entity numbers semi-recently? These older units/firmwares report a sysObjectID of .220.127.116.11.4.1.10002.1, while the newer firmwares report .18.104.22.168.4.1.8072.3.2.10 (which we're already using for OS detection) - should I add a sysObjectID check & poll the old/new OID appropriately, just poll both and look for a valid response, or something else entirely?
Edit: Argh! My bad, a few extra characters here and there. Cleaning this up, will push a new commit.
Dropped in the sysObjectID check and swapped the multiple independent snmp_get()s out for a single snmp_get_multi() for each type (old/new).
Should I be doing more sanity-checking here? OS identification happens long before we get to this bit, and AFAICT all UBNT gear should respond to this in an appropriate fashion - if we can find someone who's still running very old HW/firmware versions to test with that would be useful.
Apologies for the mess, git still does my head in. Anyway, this now attempts to pull the newer OIDs and (if that should fail) pulls the older .0 OID which is shown to work in firmwares over 3 years old.
Should we be covering the possible edge case of a device that doesn't report unifiApSystemModel.0 or dot11manufacturerName.0 but might report dot11manufacturerName.5 (or some other ID) via a couple of snmp_getnext()s if the original multi-get fails? I can't rule out the possibility that somewhere between 2014 and mid-2016 there may be a firmware that behaves like this.
I've borrowed some of the logic from snmp_get_multi() here for parsing/sanity checking since there's a nonzero chance that a getnext on one or both OIDs might return (say) sysDescr.0, and it saves an SNMP op - snmpgetnext is quite happy to operate on multiple OIDs too, perhaps an snmp_getnext_multi() function might be worth making...
Works great on my test unit (commented out the UBNT-UniFi-MIB check for this test since this AP responds to both);
Edit: And I messed this up again - with those same two superfluous s that won't leave me alone... I need to do better at this & I should have started by opening this as an issue rather than a pull request, shouldn't I?
It's pretty simple to add, too - almost a carbon copy of snmp_get_multi(), and it makes this fix a lot cleaner.
I can close this PR and go down that route? It seems like the smarter move long-term... Makes sanity checking getnext results much easier too as the returned OID gets used for the index.