Get current wardriving status.
(self)
| 2201 | 'gps_port': self._gps.port if gps_ok else None |
| 2202 | } |
| 2203 | |
| 2204 | def _ensure_hat_buttons(self): |
| 2205 | """Reclaim the 2.7" e-paper HAT buttons for Ragnar when wardriving |
| 2206 | starts, in case another app (airprint.service) holds the GPIO pins.""" |
| 2207 | try: |
| 2208 | display = getattr(self.shared_data, 'display_instance', None) |
| 2209 | listener = getattr(display, 'button_listener', None) if display else None |
| 2210 | if listener is None or not hasattr(listener, 'ensure_available'): |
| 2211 | return |
| 2212 | if listener.ensure_available(): |
| 2213 | logger.info("Wardriving: e-paper HAT buttons ready") |
| 2214 | else: |
| 2215 | logger.warning("Wardriving: could not reclaim e-paper HAT buttons") |
| 2216 | except Exception as e: |
| 2217 | logger.debug(f"HAT button reclaim skipped: {e}") |
| 2218 | |
| 2219 | @staticmethod |
| 2220 | def _iface_is_usb(iface): |
| 2221 | """True if this radio is a USB dongle (as opposed to a built-in radio).""" |
| 2222 | try: |
| 2223 | return 'usb' in os.path.realpath( |
| 2224 | f'/sys/class/net/{iface}/device').lower() |
| 2225 | except OSError: |
| 2226 | return False |
| 2227 | |
| 2228 | @staticmethod |
| 2229 | def _iface_supports_ap(iface): |
| 2230 | """True if the radio behind iface advertises AP mode (iw phy info). |
| 2231 | |
| 2232 | Built-in Pi radios do; a number of USB dongles (several Alfa cards |
| 2233 | among them) do NOT, and hostapd started on one that doesn't just fails. |
| 2234 | Fails open (True) when the mode list can't be read, so an unknown radio |
| 2235 | is never wrongly excluded. |
| 2236 | """ |
| 2237 | try: |
| 2238 | phy = os.path.basename( |
| 2239 | os.path.realpath(f'/sys/class/net/{iface}/phy80211')) |
| 2240 | r = subprocess.run(['iw', 'phy', phy, 'info'], |
| 2241 | capture_output=True, text=True, timeout=6) |
| 2242 | if r.returncode != 0: |
| 2243 | return True |
| 2244 | block = re.search(r"Supported interface modes:(.*?)(?:\n\s*\n|\Z)", |
| 2245 | r.stdout, re.S) |
| 2246 | if not block: |
| 2247 | return True |
| 2248 | return bool(re.search(r"\*\s*AP\b", block.group(1))) |
| 2249 | except Exception: |
| 2250 | return True |
| 2251 | |
| 2252 | @staticmethod |
| 2253 | def _iface_mode(iface): |
| 2254 | """Current 802.11 mode (managed/AP/monitor/…) via `iw dev info`, or None.""" |
| 2255 | try: |
| 2256 | r = subprocess.run(['iw', 'dev', iface, 'info'], |
| 2257 | capture_output=True, text=True, timeout=4) |
| 2258 | m = re.search(r'^\s*type\s+(\S+)', r.stdout, re.M) |
| 2259 | return m.group(1) if m else None |
| 2260 | except Exception: |
nothing calls this directly
no test coverage detected