68 memset(_seen, 0,
sizeof(_seen));
69 memset(_userFps, 0,
sizeof(_userFps));
70 engine._setFingerprintHook(_hook);
78 _userFps[_userFpCount++] = fp;
83 memset(_seen, 0,
sizeof(_seen));
92 uint8_t ht_cap_info[2];
100 static IeSignals _parseIe(
const uint8_t *ie, uint16_t ie_len) {
102 if (!ie || !ie_len)
return s;
104 while (pos + 2 <= ie_len) {
105 uint8_t tag = ie[pos];
106 uint8_t len = ie[pos + 1];
107 if (pos + 2 + (uint16_t)len > ie_len)
break;
108 const uint8_t *body = ie + pos + 2;
111 if (len >= 4) { s.has_rates =
true; memcpy(s.rate_sig, body, 4); }
114 if (len >= 2) { s.has_ht =
true; s.ht_cap_info[0] = body[0]; s.ht_cap_info[1] = body[1]; }
117 s.has_ext_cap =
true;
120 if (len >= 4 && body[0] == 0x00 && body[1] == 0x50 && body[2] == 0xF2) {
121 if (body[3] == 0x01) s.has_wmm =
true;
122 if (body[3] == 0x04) s.has_wps =
true;
131 static void _hook(
const uint8_t *mac,
const char *ssid, uint8_t ssid_len,
132 uint8_t ch, int8_t rssi,
const uint8_t *ie, uint16_t ie_len) {
133 if (_inst) _inst->_process(mac, ssid, ssid_len, ch, rssi, ie, ie_len);
136 void _process(
const uint8_t *mac,
const char *ssid, uint8_t ssid_len,
137 uint8_t ch, int8_t rssi,
const uint8_t *ie, uint16_t ie_len) {
138 if (mac[0] & 0x02)
return;
140 int idx = _findSeen(mac);
141 if (idx >= 0) { _seen[idx].rssi = rssi;
return; }
143 IeSignals sig = _parseIe(ie, ie_len);
145 const char *bestVendor =
nullptr;
146 const char *bestModel =
nullptr;
147 uint8_t bestConf = 0;
148 uint8_t bestFlags = 0;
150 auto applyRule = [&](
const char* vendor,
const char* probeSsid,
const char* model, uint8_t baseConf,
151 const uint8_t* ht_mask,
const uint8_t* ht_info,
const uint8_t* rate_sig,
152 uint8_t ie_flags_mask, uint8_t ie_flags) {
153 uint8_t conf = baseConf;
157 if (probeSsid && ssid_len > 0) {
158 size_t plen = strlen(probeSsid);
159 if ((
size_t)ssid_len >= plen && memcmp(ssid, probeSsid, plen) == 0) {
160 conf = (conf + 20u > 100u) ? 100u : conf + 20u;
166 if (ie && ht_mask && (ht_mask[0] || ht_mask[1]) && sig.has_ht) {
167 if ((sig.ht_cap_info[0] & ht_mask[0]) == (ht_info[0] & ht_mask[0]) &&
168 (sig.ht_cap_info[1] & ht_mask[1]) == (ht_info[1] & ht_mask[1])) {
169 conf = (conf + 15u > 100u) ? 100u : conf + 15u;
175 if (ie && rate_sig && rate_sig[0] && sig.has_rates && memcmp(sig.rate_sig, rate_sig, 4) == 0) {
176 conf = (conf + 10u > 100u) ? 100u : conf + 10u;
181 if (ie && ie_flags_mask) {
187 if ((obs & ie_flags_mask) == (ie_flags & ie_flags_mask)) {
188 conf = (conf + 5u > 100u) ? 100u : conf + 5u;
193 if (conf > bestConf) {
201 auto scanUser = [&](
const DeviceFingerprint *tbl,
size_t cnt) {
202 for (
size_t i = 0; i < cnt; i++) {
203 const DeviceFingerprint &f = tbl[i];
204 if (memcmp(f.oui, mac, 3) != 0)
continue;
205 applyRule(f.vendor, f.probeSsid, f.model, f.confidence, f.ht_cap_mask, f.ht_cap_info, f.rate_sig, f.ie_flags_mask, f.ie_flags);
209 scanUser(_userFps, _userFpCount);
211 #ifndef POLITICIAN_NO_DB
213 while (left <= right) {
214 int mid = left + (right - left) / 2;
215 int cmp = memcmp(
_FP_OUI_DB[mid].oui, mac, 3);
219 applyRule(
_FP_VENDORS[v_idx], r.probeSsid, r.model, r.confidence,
nullptr,
nullptr,
nullptr, 0, 0);
222 if (cmp < 0) left = mid + 1;
223 else right = mid - 1;
227 if (!bestVendor || bestConf < _minConf)
return;
228 _markSeen(mac, rssi);
232 memset(&rec, 0,
sizeof(rec));
233 memcpy(rec.mac, mac, 6);
234 strncpy(rec.vendor, bestVendor ? bestVendor :
"", sizeof(rec.vendor) - 1);
235 if (bestModel) strncpy(rec.model, bestModel,
sizeof(rec.model) - 1);
238 rec.confidence = bestConf;
239 rec.match_flags = bestFlags;
243 int _findSeen(
const uint8_t *mac)
const {
244 for (
int i = 0; i < _seenFill; i++)
245 if (memcmp(_seen[i].mac, mac, 6) == 0)
return i;
249 void _markSeen(
const uint8_t *mac, int8_t rssi) {
250 _seen[_seenHead].active =
true;
251 memcpy(_seen[_seenHead].mac, mac, 6);
252 _seen[_seenHead].rssi = rssi;
257 inline static Detector *_inst =
nullptr;
260 uint8_t _minConf = 50;
263 uint8_t _userFpCount;
265 struct SeenEntry {
bool active; uint8_t mac[6]; int8_t rssi; };