• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2012 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include "shill/wifi/wifi_endpoint.h"
18 
19 #include <algorithm>
20 
21 #include <base/stl_util.h>
22 #include <base/strings/stringprintf.h>
23 #include <base/strings/string_number_conversions.h>
24 #include <base/strings/string_util.h>
25 #if defined(__ANDROID__)
26 #include <dbus/service_constants.h>
27 #else
28 #include <chromeos/dbus/service_constants.h>
29 #endif  // __ANDROID__
30 
31 #include "shill/control_interface.h"
32 #include "shill/logging.h"
33 #include "shill/metrics.h"
34 #include "shill/net/ieee80211.h"
35 #include "shill/supplicant/supplicant_bss_proxy_interface.h"
36 #include "shill/supplicant/wpa_supplicant.h"
37 #include "shill/tethering.h"
38 #include "shill/wifi/wifi.h"
39 
40 using base::StringPrintf;
41 using std::map;
42 using std::set;
43 using std::string;
44 using std::vector;
45 
46 namespace shill {
47 
48 namespace Logging {
49 static auto kModuleLogScope = ScopeLogger::kWiFi;
ObjectID(WiFiEndpoint * w)50 static string ObjectID(WiFiEndpoint* w) { return "(wifi_endpoint)"; }
51 }
52 
WiFiEndpoint(ControlInterface * control_interface,const WiFiRefPtr & device,const string & rpc_id,const KeyValueStore & properties)53 WiFiEndpoint::WiFiEndpoint(ControlInterface* control_interface,
54                            const WiFiRefPtr& device,
55                            const string& rpc_id,
56                            const KeyValueStore& properties)
57     : frequency_(0),
58       physical_mode_(Metrics::kWiFiNetworkPhyModeUndef),
59       ieee80211w_required_(false),
60       control_interface_(control_interface),
61       device_(device),
62       rpc_id_(rpc_id) {
63   ssid_ = properties.GetUint8s(WPASupplicant::kBSSPropertySSID);
64   bssid_ = properties.GetUint8s(WPASupplicant::kBSSPropertyBSSID);
65   signal_strength_ = properties.GetInt16(WPASupplicant::kBSSPropertySignal);
66   if (properties.ContainsUint16(WPASupplicant::kBSSPropertyFrequency)) {
67     frequency_ = properties.GetUint16(WPASupplicant::kBSSPropertyFrequency);
68   }
69 
70   Metrics::WiFiNetworkPhyMode phy_mode = Metrics::kWiFiNetworkPhyModeUndef;
71   if (!ParseIEs(properties, &phy_mode, &vendor_information_,
72                 &ieee80211w_required_, &country_code_)) {
73     phy_mode = DeterminePhyModeFromFrequency(properties, frequency_);
74   }
75   physical_mode_ = phy_mode;
76 
77   network_mode_ = ParseMode(
78       properties.GetString(WPASupplicant::kBSSPropertyMode));
79   set_security_mode(ParseSecurity(properties, &security_flags_));
80   has_rsn_property_ =
81       properties.ContainsKeyValueStore(WPASupplicant::kPropertyRSN);
82   has_wpa_property_ =
83       properties.ContainsKeyValueStore(WPASupplicant::kPropertyWPA);
84 
85   if (network_mode_.empty()) {
86     // XXX log error?
87   }
88 
89   ssid_string_ = string(ssid_.begin(), ssid_.end());
90   WiFi::SanitizeSSID(&ssid_string_);
91   ssid_hex_ = base::HexEncode(&(*ssid_.begin()), ssid_.size());
92   bssid_string_ = Device::MakeStringFromHardwareAddress(bssid_);
93   bssid_hex_ = base::HexEncode(&(*bssid_.begin()), bssid_.size());
94 
95   CheckForTetheringSignature();
96 }
97 
~WiFiEndpoint()98 WiFiEndpoint::~WiFiEndpoint() {}
99 
Start()100 void WiFiEndpoint::Start() {
101   supplicant_bss_proxy_.reset(
102       control_interface_->CreateSupplicantBSSProxy(this, rpc_id_));
103 }
104 
PropertiesChanged(const KeyValueStore & properties)105 void WiFiEndpoint::PropertiesChanged(const KeyValueStore& properties) {
106   SLOG(this, 2) << __func__;
107   bool should_notify = false;
108   if (properties.ContainsInt16(WPASupplicant::kBSSPropertySignal)) {
109     signal_strength_ = properties.GetInt16(WPASupplicant::kBSSPropertySignal);
110     should_notify = true;
111   }
112 
113   if (properties.ContainsString(WPASupplicant::kBSSPropertyMode)) {
114     string new_mode =
115         ParseMode(properties.GetString(WPASupplicant::kBSSPropertyMode));
116     if (new_mode != network_mode_) {
117       network_mode_ = new_mode;
118       SLOG(this, 2) << "WiFiEndpoint " << bssid_string_ << " mode is now "
119                     << network_mode_;
120       should_notify = true;
121     }
122   }
123 
124   const char* new_security_mode = ParseSecurity(properties, &security_flags_);
125   if (new_security_mode != security_mode()) {
126     set_security_mode(new_security_mode);
127     SLOG(this, 2) << "WiFiEndpoint " << bssid_string_ << " security is now "
128                   << security_mode();
129     should_notify = true;
130   }
131 
132   if (should_notify) {
133     device_->NotifyEndpointChanged(this);
134   }
135 }
136 
UpdateSignalStrength(int16_t strength)137 void WiFiEndpoint::UpdateSignalStrength(int16_t strength) {
138   if (signal_strength_ == strength) {
139     return;
140   }
141 
142   SLOG(this, 2) << __func__ << ": signal strength "
143                 << signal_strength_ << " -> " << strength;
144   signal_strength_ = strength;
145   device_->NotifyEndpointChanged(this);
146 }
147 
GetVendorInformation() const148 map<string, string> WiFiEndpoint::GetVendorInformation() const {
149   map<string, string> vendor_information;
150   if (!vendor_information_.wps_manufacturer.empty()) {
151     vendor_information[kVendorWPSManufacturerProperty] =
152         vendor_information_.wps_manufacturer;
153   }
154   if (!vendor_information_.wps_model_name.empty()) {
155     vendor_information[kVendorWPSModelNameProperty] =
156         vendor_information_.wps_model_name;
157   }
158   if (!vendor_information_.wps_model_number.empty()) {
159     vendor_information[kVendorWPSModelNumberProperty] =
160         vendor_information_.wps_model_number;
161   }
162   if (!vendor_information_.wps_device_name.empty()) {
163     vendor_information[kVendorWPSDeviceNameProperty] =
164         vendor_information_.wps_device_name;
165   }
166   if (!vendor_information_.oui_set.empty()) {
167     vector<string> oui_vector;
168     for (auto oui : vendor_information_.oui_set) {
169       oui_vector.push_back(
170           StringPrintf("%02x-%02x-%02x",
171               oui >> 16, (oui >> 8) & 0xff, oui & 0xff));
172     }
173     vendor_information[kVendorOUIListProperty] =
174         base::JoinString(oui_vector, " ");
175   }
176   return vendor_information;
177 }
178 
179 // static
ModeStringToUint(const string & mode_string)180 uint32_t WiFiEndpoint::ModeStringToUint(const string& mode_string) {
181   if (mode_string == kModeManaged)
182     return WPASupplicant::kNetworkModeInfrastructureInt;
183   else if (mode_string == kModeAdhoc)
184     return WPASupplicant::kNetworkModeAdHocInt;
185   else
186     NOTIMPLEMENTED() << "Shill dos not support " << mode_string
187                      << " mode at this time.";
188   return 0;
189 }
190 
ssid() const191 const vector<uint8_t>& WiFiEndpoint::ssid() const {
192   return ssid_;
193 }
194 
ssid_string() const195 const string& WiFiEndpoint::ssid_string() const {
196   return ssid_string_;
197 }
198 
ssid_hex() const199 const string& WiFiEndpoint::ssid_hex() const {
200   return ssid_hex_;
201 }
202 
bssid_string() const203 const string& WiFiEndpoint::bssid_string() const {
204   return bssid_string_;
205 }
206 
bssid_hex() const207 const string& WiFiEndpoint::bssid_hex() const {
208   return bssid_hex_;
209 }
210 
country_code() const211 const string& WiFiEndpoint::country_code() const {
212   return country_code_;
213 }
214 
device() const215 const WiFiRefPtr& WiFiEndpoint::device() const {
216   return device_;
217 }
218 
signal_strength() const219 int16_t WiFiEndpoint::signal_strength() const {
220   return signal_strength_;
221 }
222 
frequency() const223 uint16_t WiFiEndpoint::frequency() const {
224   return frequency_;
225 }
226 
physical_mode() const227 uint16_t WiFiEndpoint::physical_mode() const {
228   return physical_mode_;
229 }
230 
network_mode() const231 const string& WiFiEndpoint::network_mode() const {
232   return network_mode_;
233 }
234 
security_mode() const235 const string& WiFiEndpoint::security_mode() const {
236   return security_mode_;
237 }
238 
ieee80211w_required() const239 bool WiFiEndpoint::ieee80211w_required() const {
240   return ieee80211w_required_;
241 }
242 
has_rsn_property() const243 bool WiFiEndpoint::has_rsn_property() const {
244   return has_rsn_property_;
245 }
246 
has_wpa_property() const247 bool WiFiEndpoint::has_wpa_property() const {
248   return has_wpa_property_;
249 }
250 
has_tethering_signature() const251 bool WiFiEndpoint::has_tethering_signature() const {
252   return has_tethering_signature_;
253 }
254 
255 // static
MakeOpenEndpoint(ControlInterface * control_interface,const WiFiRefPtr & wifi,const string & ssid,const string & bssid,const string & network_mode,uint16_t frequency,int16_t signal_dbm)256 WiFiEndpoint* WiFiEndpoint::MakeOpenEndpoint(
257     ControlInterface* control_interface,
258     const WiFiRefPtr& wifi,
259     const string& ssid,
260     const string& bssid,
261     const string& network_mode,
262     uint16_t frequency,
263     int16_t signal_dbm) {
264   return MakeEndpoint(control_interface, wifi, ssid, bssid, network_mode,
265                       frequency, signal_dbm, false, false);
266 }
267 
268 
269 // static
MakeEndpoint(ControlInterface * control_interface,const WiFiRefPtr & wifi,const string & ssid,const string & bssid,const string & network_mode,uint16_t frequency,int16_t signal_dbm,bool has_wpa_property,bool has_rsn_property)270 WiFiEndpoint* WiFiEndpoint::MakeEndpoint(ControlInterface* control_interface,
271                                          const WiFiRefPtr& wifi,
272                                          const string& ssid,
273                                          const string& bssid,
274                                          const string& network_mode,
275                                          uint16_t frequency,
276                                          int16_t signal_dbm,
277                                          bool has_wpa_property,
278                                          bool has_rsn_property) {
279   KeyValueStore args;
280 
281   args.SetUint8s(WPASupplicant::kBSSPropertySSID,
282                  vector<uint8_t>(ssid.begin(), ssid.end()));
283 
284   vector<uint8_t> bssid_bytes =
285       Device::MakeHardwareAddressFromString(bssid);
286   args.SetUint8s(WPASupplicant::kBSSPropertyBSSID, bssid_bytes);
287 
288   args.SetInt16(WPASupplicant::kBSSPropertySignal, signal_dbm);
289   args.SetUint16(WPASupplicant::kBSSPropertyFrequency, frequency);
290   args.SetString(WPASupplicant::kBSSPropertyMode, network_mode);
291 
292   if (has_wpa_property) {
293     KeyValueStore empty_args;
294     args.SetKeyValueStore(WPASupplicant::kPropertyWPA, empty_args);
295   }
296   if (has_rsn_property) {
297     KeyValueStore empty_args;
298     args.SetKeyValueStore(WPASupplicant::kPropertyRSN, empty_args);
299   }
300 
301   return new WiFiEndpoint(
302       control_interface, wifi, bssid, args);  // |bssid| fakes an RPC ID
303 }
304 
305 // static
ParseMode(const string & mode_string)306 const char* WiFiEndpoint::ParseMode(const string& mode_string) {
307   if (mode_string == WPASupplicant::kNetworkModeInfrastructure) {
308     return kModeManaged;
309   } else if (mode_string == WPASupplicant::kNetworkModeAdHoc) {
310     return kModeAdhoc;
311   } else if (mode_string == WPASupplicant::kNetworkModeAccessPoint) {
312     NOTREACHED() << "Shill does not support AP mode at this time.";
313     return nullptr;
314   } else {
315     NOTREACHED() << "Unknown WiFi endpoint mode!";
316     return nullptr;
317   }
318 }
319 
320 // static
ParseSecurity(const KeyValueStore & properties,SecurityFlags * flags)321 const char* WiFiEndpoint::ParseSecurity(
322     const KeyValueStore& properties, SecurityFlags* flags) {
323   if (properties.ContainsKeyValueStore(WPASupplicant::kPropertyRSN)) {
324     KeyValueStore rsn_properties =
325         properties.GetKeyValueStore(WPASupplicant::kPropertyRSN);
326     set<KeyManagement> key_management;
327     ParseKeyManagementMethods(rsn_properties, &key_management);
328     flags->rsn_8021x = ContainsKey(key_management, kKeyManagement802_1x);
329     flags->rsn_psk = ContainsKey(key_management, kKeyManagementPSK);
330   }
331 
332   if (properties.ContainsKeyValueStore(WPASupplicant::kPropertyWPA)) {
333     KeyValueStore rsn_properties =
334         properties.GetKeyValueStore(WPASupplicant::kPropertyWPA);
335     set<KeyManagement> key_management;
336     ParseKeyManagementMethods(rsn_properties, &key_management);
337     flags->wpa_8021x = ContainsKey(key_management, kKeyManagement802_1x);
338     flags->wpa_psk = ContainsKey(key_management, kKeyManagementPSK);
339   }
340 
341   if (properties.ContainsBool(WPASupplicant::kPropertyPrivacy)) {
342     flags->privacy = properties.GetBool(WPASupplicant::kPropertyPrivacy);
343   }
344 
345   if (flags->rsn_8021x || flags->wpa_8021x) {
346     return kSecurity8021x;
347   } else if (flags->rsn_psk) {
348     return kSecurityRsn;
349   } else if (flags->wpa_psk) {
350     return kSecurityWpa;
351   } else if (flags->privacy) {
352     return kSecurityWep;
353   } else {
354     return kSecurityNone;
355   }
356 }
357 
358 // static
ParseKeyManagementMethods(const KeyValueStore & security_method_properties,set<KeyManagement> * key_management_methods)359 void WiFiEndpoint::ParseKeyManagementMethods(
360     const KeyValueStore& security_method_properties,
361     set<KeyManagement>* key_management_methods) {
362   if (!security_method_properties.ContainsStrings(
363       WPASupplicant::kSecurityMethodPropertyKeyManagement)) {
364     return;
365   }
366 
367   const vector<string> key_management_vec =
368       security_method_properties.GetStrings(
369           WPASupplicant::kSecurityMethodPropertyKeyManagement);
370 
371   for (const auto& method : key_management_vec) {
372     if (base::EndsWith(method, WPASupplicant::kKeyManagementMethodSuffixEAP,
373                        base::CompareCase::SENSITIVE)) {
374       key_management_methods->insert(kKeyManagement802_1x);
375     } else if (base::EndsWith(method,
376                               WPASupplicant::kKeyManagementMethodSuffixPSK,
377                               base::CompareCase::SENSITIVE)) {
378       key_management_methods->insert(kKeyManagementPSK);
379     }
380   }
381 }
382 
383 // static
DeterminePhyModeFromFrequency(const KeyValueStore & properties,uint16_t frequency)384 Metrics::WiFiNetworkPhyMode WiFiEndpoint::DeterminePhyModeFromFrequency(
385     const KeyValueStore& properties, uint16_t frequency) {
386   uint32_t max_rate = 0;
387   if (properties.ContainsUint32s(WPASupplicant::kBSSPropertyRates)) {
388     vector<uint32_t> rates =
389         properties.GetUint32s(WPASupplicant::kBSSPropertyRates);
390     if (rates.size() > 0) {
391       max_rate = rates[0];  // Rates are sorted in descending order
392     }
393   }
394 
395   Metrics::WiFiNetworkPhyMode phy_mode = Metrics::kWiFiNetworkPhyModeUndef;
396   if (frequency < 3000) {
397     // 2.4GHz legacy, check for tx rate for 11b-only
398     // (note 22M is valid)
399     if (max_rate < 24000000)
400       phy_mode = Metrics::kWiFiNetworkPhyMode11b;
401     else
402       phy_mode = Metrics::kWiFiNetworkPhyMode11g;
403   } else {
404     phy_mode = Metrics::kWiFiNetworkPhyMode11a;
405   }
406 
407   return phy_mode;
408 }
409 
410 // static
ParseIEs(const KeyValueStore & properties,Metrics::WiFiNetworkPhyMode * phy_mode,VendorInformation * vendor_information,bool * ieee80211w_required,string * country_code)411 bool WiFiEndpoint::ParseIEs(
412     const KeyValueStore& properties,
413     Metrics::WiFiNetworkPhyMode* phy_mode,
414     VendorInformation* vendor_information,
415     bool* ieee80211w_required, string* country_code) {
416 
417   if (!properties.ContainsUint8s(WPASupplicant::kBSSPropertyIEs)) {
418     SLOG(nullptr, 2) << __func__ << ": No IE property in BSS.";
419     return false;
420   }
421   vector<uint8_t> ies = properties.GetUint8s(WPASupplicant::kBSSPropertyIEs);
422 
423   // Format of an information element:
424   //    1       1          1 - 252
425   // +------+--------+----------------+
426   // | Type | Length | Data           |
427   // +------+--------+----------------+
428   *phy_mode = Metrics::kWiFiNetworkPhyModeUndef;
429   bool found_ht = false;
430   bool found_vht = false;
431   bool found_erp = false;
432   int ie_len = 0;
433   vector<uint8_t>::iterator it;
434   for (it = ies.begin();
435        std::distance(it, ies.end()) > 1;  // Ensure Length field is within PDU.
436        it += ie_len) {
437     ie_len = 2 + *(it + 1);
438     if (std::distance(it, ies.end()) < ie_len) {
439       LOG(ERROR) << __func__ << ": IE extends past containing PDU.";
440       break;
441     }
442     switch (*it) {
443       case IEEE_80211::kElemIdCountry:
444         // Retrieve 2-character country code from the beginning of the element.
445         if (ie_len >= 4) {
446           *country_code = string(it + 2, it + 4);
447         }
448       case IEEE_80211::kElemIdErp:
449         found_erp = true;
450         break;
451       case IEEE_80211::kElemIdHTCap:
452       case IEEE_80211::kElemIdHTInfo:
453         found_ht = true;
454         break;
455       case IEEE_80211::kElemIdVHTCap:
456       case IEEE_80211::kElemIdVHTOperation:
457         found_vht = true;
458         break;
459       case IEEE_80211::kElemIdRSN:
460         ParseWPACapabilities(it + 2, it + ie_len, ieee80211w_required);
461         break;
462       case IEEE_80211::kElemIdVendor:
463         ParseVendorIE(it + 2, it + ie_len, vendor_information,
464                       ieee80211w_required);
465         break;
466     }
467   }
468   if (found_vht) {
469     *phy_mode = Metrics::kWiFiNetworkPhyMode11ac;
470   } else if (found_ht) {
471     *phy_mode = Metrics::kWiFiNetworkPhyMode11n;
472   } else if (found_erp) {
473     *phy_mode = Metrics::kWiFiNetworkPhyMode11g;
474   } else {
475     return false;
476   }
477   return true;
478 }
479 
480 // static
ParseWPACapabilities(vector<uint8_t>::const_iterator ie,vector<uint8_t>::const_iterator end,bool * ieee80211w_required)481 void WiFiEndpoint::ParseWPACapabilities(
482     vector<uint8_t>::const_iterator ie,
483     vector<uint8_t>::const_iterator end,
484     bool* ieee80211w_required) {
485   // Format of an RSN Information Element:
486   //    2             4
487   // +------+--------------------+
488   // | Type | Group Cipher Suite |
489   // +------+--------------------+
490   //             2             4 * pairwise count
491   // +-----------------------+---------------------+
492   // | Pairwise Cipher Count | Pairwise Ciphers... |
493   // +-----------------------+---------------------+
494   //             2             4 * authkey count
495   // +-----------------------+---------------------+
496   // | AuthKey Suite Count   | AuthKey Suites...   |
497   // +-----------------------+---------------------+
498   //          2
499   // +------------------+
500   // | RSN Capabilities |
501   // +------------------+
502   //          2            16 * pmkid count
503   // +------------------+-------------------+
504   // |   PMKID Count    |      PMKIDs...    |
505   // +------------------+-------------------+
506   //          4
507   // +-------------------------------+
508   // | Group Management Cipher Suite |
509   // +-------------------------------+
510   if (std::distance(ie, end) < IEEE_80211::kRSNIECipherCountOffset) {
511     return;
512   }
513   ie += IEEE_80211::kRSNIECipherCountOffset;
514 
515   // Advance past the pairwise and authkey ciphers.  Each is a little-endian
516   // cipher count followed by n * cipher_selector.
517   for (int i = 0; i < IEEE_80211::kRSNIENumCiphers; ++i) {
518     // Retrieve a little-endian cipher count.
519     if (std::distance(ie, end) < IEEE_80211::kRSNIECipherCountLen) {
520       return;
521     }
522     uint16_t cipher_count = *ie | (*(ie + 1) << 8);
523 
524     // Skip over the cipher selectors.
525     int skip_length = IEEE_80211::kRSNIECipherCountLen +
526       cipher_count * IEEE_80211::kRSNIESelectorLen;
527     if (std::distance(ie, end) < skip_length) {
528       return;
529     }
530     ie += skip_length;
531   }
532 
533   if (std::distance(ie, end) < IEEE_80211::kRSNIECapabilitiesLen) {
534     return;
535   }
536 
537   // Retrieve a little-endian capabilities bitfield.
538   uint16_t capabilities = *ie | (*(ie + 1) << 8);
539 
540   if (capabilities & IEEE_80211::kRSNCapabilityFrameProtectionRequired &&
541       ieee80211w_required) {
542     // Never set this value to false, since there may be multiple RSN
543     // information elements.
544     *ieee80211w_required = true;
545   }
546 }
547 
548 
549 // static
ParseVendorIE(vector<uint8_t>::const_iterator ie,vector<uint8_t>::const_iterator end,VendorInformation * vendor_information,bool * ieee80211w_required)550 void WiFiEndpoint::ParseVendorIE(vector<uint8_t>::const_iterator ie,
551                                  vector<uint8_t>::const_iterator end,
552                                  VendorInformation* vendor_information,
553                                  bool* ieee80211w_required) {
554   // Format of an vendor-specific information element (with type
555   // and length field for the IE removed by the caller):
556   //        3           1       1 - 248
557   // +------------+----------+----------------+
558   // | OUI        | OUI Type | Data           |
559   // +------------+----------+----------------+
560 
561   if (std::distance(ie, end) < 4) {
562     LOG(ERROR) << __func__ << ": no room in IE for OUI and type field.";
563     return;
564   }
565   uint32_t oui = (*ie << 16) | (*(ie + 1) << 8) | *(ie + 2);
566   uint8_t oui_type = *(ie + 3);
567   ie += 4;
568 
569   if (oui == IEEE_80211::kOUIVendorMicrosoft &&
570       oui_type == IEEE_80211::kOUIMicrosoftWPS) {
571     // Format of a WPS data element:
572     //    2       2
573     // +------+--------+----------------+
574     // | Type | Length | Data           |
575     // +------+--------+----------------+
576     while (std::distance(ie, end) >= 4) {
577       int element_type = (*ie << 8) | *(ie + 1);
578       int element_length = (*(ie + 2) << 8) | *(ie + 3);
579       ie += 4;
580       if (std::distance(ie, end) < element_length) {
581         LOG(ERROR) << __func__ << ": WPS element extends past containing PDU.";
582         break;
583       }
584       string s(ie, ie + element_length);
585       if (base::IsStringASCII(s)) {
586         switch (element_type) {
587           case IEEE_80211::kWPSElementManufacturer:
588             vendor_information->wps_manufacturer = s;
589             break;
590           case IEEE_80211::kWPSElementModelName:
591             vendor_information->wps_model_name = s;
592             break;
593           case IEEE_80211::kWPSElementModelNumber:
594             vendor_information->wps_model_number = s;
595             break;
596           case IEEE_80211::kWPSElementDeviceName:
597             vendor_information->wps_device_name = s;
598             break;
599         }
600       }
601       ie += element_length;
602     }
603   } else if (oui == IEEE_80211::kOUIVendorMicrosoft &&
604              oui_type == IEEE_80211::kOUIMicrosoftWPA) {
605     ParseWPACapabilities(ie, end, ieee80211w_required);
606   } else if (oui != IEEE_80211::kOUIVendorEpigram &&
607              oui != IEEE_80211::kOUIVendorMicrosoft) {
608     vendor_information->oui_set.insert(oui);
609   }
610 }
611 
CheckForTetheringSignature()612 void WiFiEndpoint::CheckForTetheringSignature() {
613   has_tethering_signature_ =
614       Tethering::IsAndroidBSSID(bssid_) ||
615       (Tethering::IsLocallyAdministeredBSSID(bssid_) &&
616        Tethering::HasIosOui(vendor_information_.oui_set));
617 }
618 
619 }  // namespace shill
620