6.4 KiB
Wi-Fi AP 서브시스템 가이드
살아있는 문서(living guide) — 앱 v1.11.10 기준. 코드:
src/network/ap_*.py,deploy/dpworld-ap-apply.sh. 아키텍처 전체는architecture.md§3.1.1.
장비를 소프트 AP(ap0)로 띄워 운영자가 무선으로 Web Configurator(:9090)에 접속하게 한다.
STA(wlan0, 업스트림 Wi-Fi)는 무접촉으로 유지한다.
1. ap0 가상 인터페이스 (vif)
wlan0위에iw dev wlan0 interface add ap0 type __ap로 별도 vif 생성.- MAC:
wlan0MAC 첫 옥텟에 local-admin bit(0x02)를 OR 해서 별도 MAC 부여 (ap_mac()indpworld-ap-apply.sh) — STA 와 충돌하지 않는 LA-bit 주소. - 채널 = SCC(Single-Channel Concurrency): 기본(
ap_band=auto)은 STA 가 붙어 있는 채널을 추종한다(ap_engine.resolve_channel). 단일 라디오는 동시에 한 채널만 쓸 수 있어, STA 와 AP 가 같은 채널이어야 둘 다 동작한다. STA 미연결 시 2.4GHz 채널 6 으로 폴백.2g/5g명시(MCC)는 옵트인이며 STA 와 채널이 갈리면 한쪽이 끊길 수 있다.
2. ap_engine 라이프사이클
ApEngine(src/network/ap_engine.py)이 적용을 오케스트레이션한다. 직렬화 lock 으로
동시 apply 의 tmp 파일 경합·서비스 중복 start 를 막는다.
ap_config→ intent 정규화(ap_model.ap_intent_from_db).validate_ap()hard-rule 검증 → 실패 시 상태REJECTED(파일 미작성).- 활성화면: 채널 산정 →
hostapd-ap0.conf/udhcpd-ap0.conf렌더(0600, 디렉터리 0700) → markerap-enabled작성. 비활성화면 marker 제거. systemctl start dpworld-ap-apply.service트리거(oneshot,dpworld-ap-apply.sh실행).- 결과 상태 persist:
APPLYING→COMMITTED/FAILED.
상태값: REJECTED, APPLYING, COMMITTED, FAILED.
marker = kill-switch
/home/root/network/ap/ap-enabled 파일의 존재 여부가 enable/disable 판정 기준이다.
dpworld-ap-apply.sh 는 marker 가 있으면 ap_up, 없으면 ap_down(멱등 정리)을 한다.
3. ap_config DB 키 + 필드
별도 board_config 키 — Python 전용(device_config 무관, Java/dpworldapp 미사용).
db_manager.ALLOWED_KEYS 에 등록됨. 기본값(ap_model.DEFAULT_AP_CONFIG):
| 필드 | 기본값 | 설명 |
|---|---|---|
ap_enabled |
false |
AP on/off |
ap_ssid |
"" |
SSID (최대 32 byte, "·\·#·제어문자 금지) |
ap_passphrase |
"" |
WPA2-PSK passphrase (8–63 byte, 동일 금지문자) |
ap_band |
"auto" |
auto(SCC) / 2g / 5g |
ap_channel |
0 |
0 = auto. band 별 유효 채널만 허용 |
ap_hidden |
false |
SSID 브로드캐스트 숨김 |
ap_ip |
192.168.50.1 |
AP 게이트웨이 IP (/24) |
dhcp_start |
192.168.50.50 |
DHCP 풀 시작 (AP 서브넷 내) |
dhcp_end |
192.168.50.150 |
DHCP 풀 끝 |
dhcp_lease |
43200 |
리스 시간(초) |
검증은
ap_validator.validate_ap— SSID/PSK 바이트 길이, hostapd-conf 인젝션 차단 (#·따옴표·역슬래시·개행), 채널-밴드 정합, DHCP 범위가 AP /24 서브넷 안인지·AP IP 와 겹치지 않는지, 그리고 유효한 country regdomain 이 있어야 활성화 가능 (country_pending이면 "reboot required").
4. systemd 유닛 (deploy/)
| 유닛 | 역할 |
|---|---|
dpworld-ap-apply.service |
oneshot — dpworld-ap-apply.sh 실행(엔진이 on-demand start, [Install] 없음). --boot(seed)/무인자(on-demand) |
dpworld-ap-seed.service |
부팅 시 marker 기준 AP 재구성(seed) |
dpworld-hostapd-ap0.service |
hostapd /home/root/network/ap/hostapd-ap0.conf |
dpworld-udhcpd-ap0.service |
udhcpd (ap0 DHCP 서버) |
dpworld-ap-apply.sh 가 vif 생성 → MAC 설정 → IP 부여 → 방화벽 → hostapd/udhcpd restart 순으로
멱등 reconcile 한다(ap_up). 어느 단계든 실패하면 ap_down 으로 fail-closed.
5. 방화벽 (v1.11.7)
ap0 전용 iptables chain(DPWORLD_AP_IN / DPWORLD_AP_FWD)을 쓴다 — STA/eth 무영향.
- INPUT(장치 자체): 전면 개방(SSH 22 포함). 즉 WPA2 PSK 가 유일한 접근 게이트. (이전 default-deny[9090/DHCP/ICMP 만 허용]에서 v1.11.7 에 전환 — 현장 관리 접근성 우선, 비밀번호 강화 전제.)
- FORWARD(경유): blanket DROP.
ip_forward=1이어도 AP 클라이언트가 PLC(eth1)·업링크로 라우팅하는 것을 전면 차단 = provisioning 격리(PLC/내부망 보호). 이 격리는 유지된다.
★ 요약: AP 클라이언트는 장치 자체엔 접근 가능하나(PSK 통과 시), 내부망/PLC 로는 경유 불가.
6. API
| Method | Path | 비고 |
|---|---|---|
GET |
/api/network/ap/status |
라이브 상태 — 응답에서 ap_passphrase 제거(미인증 API) |
POST |
/api/network/ap/config |
ap_config 저장(필드 화이트리스트 merge, 알 수 없는 키 400) |
POST |
/api/network/ap/apply |
bring-up/down 적용. {"dry_run": true} 면 적용 없이 config 회신(PSK 제거) |
status 응답: ap_enabled·ap0_up·hostapd_running·clients·country_pending + 마스킹된 config.
서브시스템 import 실패(예: Windows dev box) 시 503 fail-soft.
API 인증 없음: :9090 은 현재 미인증(문서화된 threat boundary). AP 가 열리면 PSK 만이 게이트이므로 강한 AP PSK 가 사실상의 1차 방어선이다. 운영자 로그인은 설계 백로그 (
architecture.md§10).
7. kill-switch (수동 비활성화)
엔진/웹이 응답하지 않을 때 root 셸에서 즉시 AP 를 내릴 수 있다:
rm /home/root/network/ap/ap-enabled && /usr/bin/dpworld-ap-apply.sh
marker 가 사라지면 스크립트가 ap_down(데몬 stop + 방화벽 flush + ap0 삭제)을 수행한다.
8. ⚠ flash 생존 caveat
/home/root/network/ap/*(config·marker)와 /opt 상태는 펌웨어 flash 후에도 생존한다.
그러나 deploy/ 의 systemd 유닛·dpworld-ap-apply.sh 는 rootfs(/lib, /usr/bin)에 설치되며
flash 마다 wipe 된다. 따라서 flash 후에는 AP 유닛/스크립트를 재설치해야 AP 가 다시 뜬다.
근본 해결(BSP 이미지 베이킹)은 백로그 — firmware-ota-guide.md §6 및 메모리
web-survives-flash 참조.