Skip to content

Repository files navigation

PPPoE VLAN GPON Diagnostics — Fix PPPoE Error 651 on GPON Fiber

Fix PPPoE Error 651 · Diagnose “No PADO” · 802.1Q VLAN Sweep 1–4094 · GPON / ONU / OLT Analysis

A packet-level, bottom-up PowerShell toolkit and a fully evidence-backed case study of a fiber connection that never authenticated — root-caused to the operator’s OLT.

License: MIT PowerShell Tools Self-test Approach Evidence Root Cause Secrets PRs welcome

🌐 Language / زبان: English (this document) · فارسی — Persian


PPPoE VLAN GPON Diagnostics is an open-source PPPoE and GPON fiber troubleshooting toolkit for Windows, written in PowerShell. Use it to find out why a fiber line will not connect — when the ONT shows a healthy optical link but PPPoE dial-up fails with Windows error 651 and no PADO packet ever comes back.

It ships 116 diagnostic tools that:

  • sweep every 802.1Q VLAN ID from 1 to 4094 looking for a PPPoE Access Concentrator,
  • build and decode raw PPPoE Discovery frames (PADI / PADO / PADR / PADS / PADT),
  • read Huawei ONT optical power, PON/PLOAM state, GEM ports and T-CONTs over HTTP and the telnet engineering CLI,
  • and prove the capture pipeline itself is not blind before you trust a silent result.

The repository also contains the complete, reproducible investigation that used these tools to isolate a real 8-month outage to an ISP-side OLT provisioning gap — plus a ready-to-send hand-off letter you can give your operator.

🔎 Searching for one of these?   PPPoE error 651 fiber · no PADO received · GPON ONU registered but no internet · which VLAN does my ISP use · 802.1Q VLAN scanner Windows · Huawei HG8310M telnet commands · ONU state O5 but PPPoE fails · GEM port not provisionedsee the FAQ.


TL;DR — After a full bottom-up, packet-level investigation (VLAN 1–4094 sweep, a fixed-and-proven analyzer, and telnet engineering-CLI diagnostics), the verified root cause is that the OLT registered the ONU (state O5, ONU-ID 43) but never provisioned a data-service GEM port / T-CONT / service-VLAN / bridge via OMCI. The upstream PADI is therefore dropped at the PON layer, so no PADO returns on any VLAN. This is an ISP / OLT-side provisioning gapnot a modem, VLAN, firmware, or optical fault, and no ONT firmware upgrade can fix it.

⚠️ Privacy: every credential, serial number, MAC address, public IP and hostname in this repository has been masked (<REDACTED_*>). See §11.

📄 ISP hand-off: a ready-to-send, bilingual (EN + FA) provisioning request for the operator is in docs/ISP_HANDOFF.md.


⚡ Quick start

Prerequisites: Windows with PowerShell 5.1+ (or pwsh 7+), Npcap installed in WinPcap-compatible mode, and Wireshark (for tshark / dumpcap).

# 0. Clone, and turn on the secret-leak guard (recommended)
git clone https://github.com/0xRadikal/pppoe-vlan-gpon-diagnostics.git
cd pppoe-vlan-gpon-diagnostics
git config core.hooksPath .githooks

# 1. FIRST: prove the toolchain can actually detect a reply.
#    A silent VLAN sweep is meaningless if your analyzer is blind.
pwsh -File tools/fvselftest.ps1        # expect: 22 passed, 0 failed

# 2. Point the tools at your own machine (nothing is hard-coded)
$env:FV_MODEM_IP = '192.168.100.1'     # your ONT's management IP
$env:FV_MODEM_PW = '<your-password>'   # never committed; read from the environment

# 3. Sweep every VLAN for a PPPoE Access Concentrator, then analyse
pwsh -File tools/vlan_scanner.ps1

No PADO on any VLAN? Then the problem is upstream of your VLAN tag — jump straight to §6 · Root Cause and §7 · What the ISP Must Do.


📑 Table of Contents

  1. Overview
  2. Topology
  3. Methodology — Trust Nothing, Verify Everything
  4. PPPoE / GPON Primer
  5. Key Findings
  6. Root Cause (Verified, Not Guessed)
  7. What the ISP Must Do
  8. Repository Layout
  9. Complete Tool Reference (every file, linked)
  10. Telnet Command Lists
  11. Security & Privacy
  12. Status & Remaining Work
  13. FAQ — Common PPPoE / GPON Questions
  14. Glossary
  15. Contributing, License & Citation

1 · Overview

A residential GPON fiber line fails to establish a PPPoE session (Windows error 651 = "the remote computer did not respond") and has done so for roughly 8 months, even though the optical layer is perfectly healthy (PLOAM state O5, normal Rx/Tx power).

This repository is the complete, auditable record of the investigation:

  • the tooling built to generate and capture packet-level evidence (PowerShell + C# P/Invoke to wpcap.dll, driven remotely over a reverse-SSH tunnel — the Windows host has no Python);
  • the experiments run (a full VLAN 1–4094 discovery sweep, positive-control injection, dial captures, web-UI probing, telnet engineering-CLI diagnostics);
  • and the verified root cause with the exact evidence that supports it.

Every claim below is backed by a captured frame or a device-CLI readout. No guessing.


2 · Topology

┌────────┐   ┌──────────────────┐   reverse SSH    ┌────────────────────┐
│ Agent  │──▶│ Ubuntu server     │──127.0.0.1:2222─▶│ Windows 10 host     │
└────────┘   │ <REDACTED_SERVER_IP> │   tunnel        │ <REDACTED_HOSTNAME> │
             └──────────────────┘                    └─────────┬──────────┘
                                                               │ Realtek Ethernet NIC
                                                               ▼
                                              ┌──────────────────────────────┐
                                              │ Hyper-V External vSwitch       │
                                              │  "PPPoE-VLAN827"  (+ MonTrunk) │
                                              └───────────────┬────────────────┘
                                                              ▼
                                              ┌──────────────────────────────┐
                                              │ Huawei HG8310M ONT             │
                                              │ 192.168.100.1 · pure bridge    │
                                              └───────────────┬────────────────┘
                                                              ▼ GPON fiber
                                              ┌──────────────────────────────┐
                                              │ Fiberhome OLT (ISP)            │
                                              └───────────────┬────────────────┘
                                                              ▼
                                                         Internet / BRAS

Injection / sniffing plane: because the physical NIC is hidden beneath the Hyper-V vSwitch and invisible to Npcap, a second trunk-mode management vNIC — MonTrunk — is attached to the same vSwitch as an inject-and-sniff port (Npcap device \Device\NPF_{…E684ADD}). All raw 802.1Q-tagged PPPoE frames are sent and captured there.


3 · Methodology — Trust Nothing, Verify Everything

The investigation followed the OSI stack bottom-up (L1 → L7) and applied two independent techniques to make every result trustworthy rather than merely plausible:

# Principle How it was enforced
1 Positive control Before trusting any "0 PADO" result, synthetic PADO/PADS frames were injected on VLAN 827 to prove the detector is not blind (see positive_control.ps1).
2 Cross-layer corroboration The L2 sweep result was cross-checked against the ONT's own GPON engineering-CLI counters over telnet — two independent sources agreeing.
3 Well-formedness proof Our own PADIs were verified to be correctly 802.1Q-tagged (eth.type==0x8100, vlan.etype==0x8863) before concluding "no reply" (see deep_frame_probe.ps1).
4 Field-name verification The tshark filter fields themselves were validated — which uncovered a real analyzer bug (below).

🐞 The analyzer bug that was found and fixed

The original analyzer filtered on pppoed.code==0x07. That field does not exist: the protocol filter is pppoed, but the code field lives on the parent PPPoE layer and is pppoe.code (Host-Uniq is pppoed.tags.host_uniq).

The failure mode is worse than returning zero — tshark aborts the whole command:

$ tshark -r capture.pcapng -Y "pppoed.code==0x07"
tshark: Neither "pppoed.code" nor "0x07" are field or protocol names.

$ tshark -r capture.pcapng -T fields -e pppoed.code
tshark: Some fields aren't valid:
        pppoed.code            # ← no output at all

Because the callers redirect stderr to $null and run with $ErrorActionPreference='SilentlyContinue', that error was invisible: the operator saw an empty result and read it as "no PADO", when in reality no search ran at all. A real PADO would have been missed.

  • After the fix, the positive control correctly reported PADO=6 / PADS=6 and extracted vlan.id=827 — proving the analyzer now works.
  • The full 4094-VLAN sweep was then re-analysed and still showed 0 PADO everywhere — now a trustworthy zero.

This is exactly why the "check your own scanner, maybe it has a bug" instruction mattered: the suspicion was correct, and the bug was real.

⚠️ Follow-up audit: the fix was originally incomplete

A later audit of the published tree found the correction had only been applied to 2 of 32 scripts — 26 files still used the invalid pppoed.code, and scanner_selfcheck.ps1 also used a non-existent pppoed.tag.host_uniq (the correct name is plural: pppoed.tags.host_uniq). Those files were silently producing no output. All of them are now fixed, and the toolchain ships a self-test that makes this class of bug impossible to reintroduce unnoticed:

.\tools\fvselftest.ps1     # exit 0 = a "0 PADO" result is meaningful

fvselftest.ps1 synthesises a capture that provably contains a PADI/PADO/PADR/PADS/PADT set, then asserts that every field name and display filter used in this repository finds exactly what it should (22 assertions). It requires only tshark — no ONT, no Npcap, no hardware. If it fails, no capture result from these tools may be trusted.

diag_fields.ps1 intentionally still probes both spellings — that is the tool whose job is to demonstrate which name is correct.


4 · PPPoE / GPON Primer

PPPoE Discovery stage (click to expand)
Frame Code EtherType Direction
PADI — Initiation 0x09 0x8863 (discovery) client → broadcast
PADO — Offer 0x07 0x8863 server → client
PADR — Request 0x19 0x8863 client → server
PADS — Session-confirm 0x65 0x8863 server → client
PADT — Terminate 0xa7 0x8863 either
session data 0x8864 (session) both

If the client sends PADI and never receives PADO, Windows reports error 651. The whole investigation is essentially: "why does our PADI never earn a PADO?"

802.1Q VLAN tagging & GPON PLOAM state machine (click to expand)
  • 802.1Q tag EtherType = 0x8100; VLAN 827 = 0x033b.
  • GPON PLOAM registration: O1 → O2 → O3 (ranging / SN) → O4 → O5 (operational). ONU-ID is assigned during O3 → O4.
  • After registration the OLT pushes the data service (GEM port + T-CONT + service-VLAN + bridge mapping) to the ONU via OMCI. This is the step that is missing here.

5 · Key Findings

5.1 Full VLAN sweep (1–4094)

One 802.1Q-tagged PADI was transmitted per VLAN (Host-Uniq encodes the VLAN id so any reply could be attributed to its VLAN). Result:

0 PADO / 0 PADS across all 4094 VLANs.

VLAN 827 is therefore not "the wrong VLAN"no VLAN answers at all. The fault lies below the PPPoE/VLAN layer.

5.2 Telnet engineering-CLI diagnosis (the decisive evidence)

Telnet (port 23) is open; engineer shell reached via <TELNET_USER>suSU_WAP>:

Command Result Interpretation
display onu info onuid:43 · reg status:O5 ONU is fully registered; OLT accepted the SN & assigned ONU-ID 43
PLOAM log O1→O2→O3→O4→O5 Ranging + registration succeeded → SN/PLOAM auth is NOT the problem
display optic Rx ≈ −24.2 dBm / Tx ≈ +2.3 dBm Optics normal
display pon statistics (2 snapshots) Rx gem +15 000, Tx gem frozen, Tx octets = 0, Tx unicast = 0 Downstream floods arrive; no user data ever leaves upstream
display poncnt gemport upstatistic ERROR 0xfc000105 No upstream data GEM port exists
display wan layer all (empty) Pure bridge (expected)
display macaddress PC MAC learned on Port 1 / VLAN 1 LAN → ONT bridge path is healthy

The single most damning number: Tx octets = 0 — over its entire uptime the ONU has sent zero user bytes upstream (only OMCI management traffic). There is simply no upstream data path for a PADI to travel through.


6 · Root Cause (Verified, Not Guessed)

The ONT is optically synced and GPON-registered (O5, ONU-ID 43), but the OLT has NOT provisioned a data-service GEM port + T-CONT + service-VLAN + bridge mapping (normally pushed via OMCI after registration) for this ONU.

Consequently the upstream PADI is dropped at the PON layer, so no PADO ever returns — on any VLAN. This is an OLT-side (ISP) service-provisioning gap, not a modem-config, VLAN, firmware, or optical fault.

Why a firmware upgrade cannot fix this

The missing piece (GEM / T-CONT / service-VLAN profile) is pushed by the OLT via OMCI. No ONT firmware version can synthesise an upstream data service the OLT has not provisioned. Firmware may be upgraded for stability, but it cannot substitute for OLT-side service configuration.


7 · What the ISP Must Do

The ONU is registeredONU-ID 43, state O5, SN <REDACTED_SN>, Rx ≈ −24.2 dBm. Please add / repair the DATA service for this ONU on the OLT:

  • a GEM port bound to a T-CONT,
  • carrying the correct service VLAN,
  • with a bridge / line-profile so PPPoE (EtherType 0x8863 / 0x8864) is carried upstream to the BRAS.

Currently there is no upstream data GEM (Tx octets = 0), so the PPPoE PADI never reaches the BRAS and no PADO is ever returned.

📄 A ready-to-send, bilingual (English + Persian) version of this request — with the full evidence table — is provided in docs/ISP_HANDOFF.md.


8 · Repository Layout

pppoe-vlan-gpon-diagnostics/
├── README.md                 ← this document (English)
├── README.fa.md              ← Persian translation (نسخهٔ فارسی)
├── .gitignore                ← excludes secrets & packet captures
├── docs/
│   ├── SESSION_LOG.md        ← full, timestamped investigation log + root cause
│   └── ISP_HANDOFF.md        ← bilingual (EN+FA) ISP provisioning hand-off
├── telnet-cmds/              ← read-only telnet command lists (see §10)
│   ├── tcmds_read.txt
│   ├── tcmds_omci.txt
│   ├── tcmds_omci2.txt
│   ├── tcmds_flow.txt
│   └── tcmds_gem.txt
└── tools/                    ← 116 PowerShell + shell tools (see §9)
    ├── fvconfig.ps1          ← shared config: resolves MAC / tshark / Npcap / creds
    └── fvselftest.ps1        ← proves the toolchain is not blind (run this first)

8.1 · Configuration — nothing sensitive is hard-coded

Every environment-specific value (host MAC, Npcap device GUID, Wireshark path, passwords) is resolved at run time by tools/fvconfig.ps1. Earlier revisions hard-coded a real MAC and a machine-specific Npcap GUID, and — after the public scrubbing pass — left literal <REDACTED_MAC> / <REDACTED_WEB_PW> strings being used as live values, which produced tshark: Syntax error near "<" and failed web logins. Nothing is hard-coded now, and an unresolvable value raises a clear error instead of failing silently.

Variable Purpose Default
FV_SRC_MAC MAC used to send PADIs / identify our own frames auto-detected from the first Up physical adapter
FV_ADAPTER adapter name to derive the MAC and Npcap GUID from
FV_MONTRUNK_MAC Hyper-V monitor/trunk vNIC MAC unset → clause omitted from filters
FV_NPCAP_DEV capture/inject device, e.g. \Device\NPF_{GUID} derived from FV_ADAPTER
FV_NPCAP_DEV_PHYS / FV_PHYS_ADAPTER physical NIC below the vSwitch (where the vSwitch's 802.1Q tag is visible) first Up physical adapter, else FV_NPCAP_DEV
FV_NPCAP_DEV_VNIC / FV_VNIC_ADAPTER VLAN vEthernet vNIC above the vSwitch FV_NPCAP_DEV
FV_WIRESHARK_DIR Wireshark folder PATH, then the standard install locations
FV_MODEM_IP / FV_MODEM_USER ONT web UI 192.168.100.1 / telecomadmin
FV_MODEM_PW ONT web password — required, never committed none (raises an error)
FV_TELNET_CREDS / FV_TELNET_CREDS_FILE telnet creds as user:pass falls back to the web credentials
# 1. verify the toolchain can actually detect a reply (no hardware needed)
.\tools\fvselftest.ps1

# 2. point the tools at this machine
$env:FV_ADAPTER  = 'MonTrunk'
$env:FV_MODEM_PW = '<ont-web-password>'
. .\tools\fvconfig.ps1 ; Show-FvConfig      # prints resolved values, never the password

# 3. sweep, then analyse
.\tools\vlan_scanner.ps1 -Start 1 -End 4094
.\tools\scan_analyze.ps1 -Pcap C:\Windows\Temp\scan_1_4094.pcapng

⚠️ do_reboot.ps1 is the only service-interrupting tool. It now requires explicit confirmation — use -WhatIf to preview, -Force for unattended runs.

📄 Full narrative: docs/SESSION_LOG.md · ISP hand-off: docs/ISP_HANDOFF.md · Persian README: README.fa.md


9 · Complete Tool Reference

Every file under tools/ is listed below, grouped by purpose, with a direct link and a description of what it does and why it exists. The tools were built iteratively during a live investigation, so some groups contain several evolutionary variants of the same idea — these are all kept for a complete, auditable record and are marked accordingly.

Legend: ⭐ = primary/decisive tool · 🔁 = evolutionary variant/iteration · 🧪 = one-off experiment

9.0 · Star tools (start here)

Tool What it does
fvselftest.ps1 Run this first. Builds a synthetic capture that provably contains PADI/PADO/PADR/PADS/PADT, then asserts that every field name and display filter this repo uses finds exactly what it should (22 assertions). Needs only tshark — no ONT, no Npcap, no hardware. Exit 0 is the precondition for trusting any "0 PADO" result.
fvconfig.ps1 Shared configuration module (dot-sourced by every tool). Resolves the source MAC, Npcap device, tshark/dumpcap paths and modem/telnet credentials at run time from environment variables or live adapter discovery, and throws when a value cannot be resolved — so no placeholder can ever be used as a live value. Show-FvConfig prints what was resolved (never the password). See §8.1.
vlan_scanner.ps1 The VLAN scanner. C# P/Invoke to wpcap.dll; sends one 802.1Q-tagged PADI per VLAN on the MonTrunk trunk port, encoding the VLAN id in the Host-Uniq tag ("VL"+hi+lo) so replies can be attributed. Params -Start 1 -End 4094, 8 ms spacing. This is the engine of the full 1–4094 sweep.
scan_analyze.ps1 The analyzer (bug-fixed). tshark-based; counts PADO/PADS and extracts VLAN + Host-Uniq. Contains the critical pppoed.codepppoe.code fix for Wireshark 4.6.5 — now applied across all analyzer scripts, not just this one (see the follow-up audit). Usage: scan_analyze.ps1 -Pcap <capture.pcapng>.
positive_control.ps1 Proves the analyzer is not blind. Injects synthetic PADO (0x07) + PADS (0x65) frames on VLAN 827 (fake server MAC → our MAC) via wpcap, then confirms scan_analyze.ps1 detects them. Validated PADO=6/PADS=6.
diag_fields.ps1 Field-name discovery. Runs the positive-control pcap through both pppoed.code and pppoe.code filters to prove which field name is correct in tshark 4.6.5. This is how the analyzer bug was pinned down.
deep_frame_probe.ps1 Proves our PADIs are well-formed. Confirms eth.src==our MAC, eth.type==0x8100, vlan.etype==0x8863 — i.e. our probes really are correctly VLAN-tagged PPPoE-discovery frames before we conclude "no reply".
telnet_login2.ps1 The telnet key. Raw-TCP telnet client (no telnet.exe dependency) with IAC negotiation and a credential-fallback list; on success runs ? to enumerate the CLI and probes su (engineer mode). Read-only. (Working credentials masked.)
telnet_run.ps1 The telnet workhorse. Generic runner: logs in, enters su (SU_WAP>), then executes a list of commands from a -CmdFile and prints each command + output. Reads credentials from an external file (not hard-coded). Used with the telnet-cmds/ lists.
finalize.ps1 Restore-to-stable. Returns the main vNIC to untagged (so the modem web panel + management path stay reachable), keeps MonTrunk enabled, and writes a ready-to-run "go-live" script to re-tag VLAN 827 and dial the moment the ISP provisions the service.

9.1 · Environment & vSwitch setup

Tool What it does
caps.ps1 Reports Windows edition, Hyper-V feature/module state, and NIC driver info — a capability snapshot of the host.
mkvsw.ps1 Creates the External Hyper-V vSwitch bound to the Realtek NIC (AllowManagementOS=true) and resets the driver-level RegVlanid to 0.
vsw.ps1 Lists existing VM switches, host vNICs, and all net adapters (including hidden/virtual).
trunkcap.ps1 Adds the second management vNIC MonTrunk on the same vSwitch in trunk mode (AllowedVlanIdList 1-1000) so 802.1Q tags are visible to capture.
cleanmon.ps1 Disables all L3 protocol bindings on MonTrunk (but not Npcap) so RAS/PPPoE can't accidentally use it — keeps it a pure sniffer.
chkmon.ps1 Prints the current protocol bindings on MonTrunk and PPPoE-VLAN827.
whichnic.ps1 Maps every adapter's MAC/ifIndex/status/description — used to identify which vNIC is which.
iflist.ps1 Lists dumpcap capture interfaces and maps NetAdapter name → GUID (needed to build the \Device\NPF_{GUID} path).
caplist.ps1 Prints the dumpcap version and its numbered capture-interface list.
pychk.ps1 Checks whether Python / Scapy exist on the host — they don't, which is why the C#/wpcap approach was chosen.
inspect.ps1 Inspects NIC filter-driver stacking, ESET/firewall processes, Windows Firewall profiles, and RAS/PPPoE phonebook entries.

9.2 · VLAN configuration & verification

Tool What it does
setvlan.ps1 Reads and sets the driver-level RegVlanid (VLAN 827) advanced property on the physical Ethernet adapter.
vlandef.ps1 Shows the current RegVlanid value and the IP config on Ethernet.
vlanverify.ps1 Confirms RegVlanid and restarts the adapter to force the VLAN setting to apply.
vlanproof.ps1 Clears ARP and pings the modem to prove the VLAN vNIC path works.
vlantest.ps1 🧪 Captures and counts how many frames actually carry a VLAN tag — an early check that tagging is happening.
untag.ps1 Sets the PPPoE-VLAN827 vNIC back to untagged and re-tests the modem HTTP GET (restore reachability).
vsweep.ps1 🔁 Parametrised access/trunk VLAN setter (-Mode access -Vlan 827) used as a building block by the sweep scripts.
multisweep.ps1 🔁 Dials across a small explicit VLAN list (e.g. 838,10,11,20,100) and reports PPPoE results — a pre-cursor to the full scanner.
quicksweep.ps1 🔁 Fast two/three-VLAN dial sweep for quick spot-checks.
bgsweep.ps1 🔁 Background sweep: sets a VLAN, dials, captures, and analyzes — an automation harness.
run_827.ps1 🔁 Sets the vNIC to VLAN 827, dials, captures on MonTrunk, and reports PPPoE codes.
run_311.ps1 🔁 Same harness targeting VLAN 311 (candidate VLAN test).
run_312.ps1 🔁 Same harness targeting VLAN 312 (candidate VLAN test).
run_unt.ps1 🔁 Same harness in the untagged case (PC untagged, ONT tags).
run827.ps1 🔁 Minimal one-liner wrapper that invokes the VLAN-827 run.

9.3 · Dial + capture (PPPoE PADI generation)

These scripts set VLAN 827, start a dumpcap capture on MonTrunk, then trigger a PPPoE dial (rasdial "Broadband Connection") so a real PADI is emitted and any reply would be captured. They differ mainly in how aggressively they dial and how wide the capture window is.

Tool What it does
cap_dial.ps1 🔁 Baseline: start capture → one dial attempt → stop → keep pcap for analysis.
cap2.ps1 🔁 Capture + single dial, filtering the rasdial output for error/success codes.
cap2way.ps1 🔁 Two-way capture variant that reads creds and reports the dial line + PPPoE frames.
cap3.ps1 🔁 Capture + dial specifically on VLAN 827.
cap827.ps1 🔁 Captures on the physical Realtek (below the vSwitch) to see the tag the vSwitch applies.
captest.ps1 🧪 Sanity test of dumpcap itself, routing stderr to a file to debug capture start-up.
dial827.ps1 🔁 Just dials over the VLAN-827 vSwitch and prints the rasdial status (no capture).
dbg_dial.ps1 🔁 Parametrised (-Vlan) debug dial: enables MonTrunk, sets VLAN, captures 16 s, dials, then dumps all PPPoED frames + distinct PADI source MACs.
mondial.ps1 🔁 Finds the MonTrunk NPF device, captures, and dials — monitor-port dial harness.
megadial.ps1 🔁 Hammer dial: 45 s capture, dials 6× to guarantee multiple PADI bursts, then summarises our_PADI / PADO / inbound_real_PPPoED (filtering out our own + MonTrunk MAC).
proof_padi.ps1 Dials 3× inside a 22 s window and proves our tagged PADI (0x09, vlan 827) frames actually appear on the wire, then reports PADO count and restores untagged.
final_probe.ps1 🔁 Late-stage combined set-VLAN → capture → dial → analyze probe.
passive_listen.ps1 🧪 Passive listen only: main vNIC untagged, just observe what the network/ONT emits unsolicited.
physcap_test.ps1 🧪 Disables MonTrunk so RAS is forced onto the tagged path, then captures — a control for "is MonTrunk interfering?".
scenarioB.ps1 🧪 Scenario B (PC untagged, ONT tags): dials untagged and compares what the PC sends (vEthernet-827) vs what appears on the trunk — tests whether the ONT itself should add the tag.
scenarioB2.ps1 🧪 Scenario B refinement: 22 s capture, dials twice to generate multiple PADI bursts, then lists all PPPoE frames + distinct VLAN ids seen.

9.4 · Capture analyzers (tshark)

Tool What it does
analyze.ps1 🔁 Minimal: total packet count in a pcap.
analyze2.ps1 🔁 Details PPPoE-Discovery frames and decodes the code byte (0x09/0x07/0x19/0x65).
analyze3.ps1 🔁 Adds a protocol-hierarchy view plus PPPoE VLAN + code listing.
analyze_ms.ps1 🔁 Per-file tallies of tagged PADI, any PADI, PADO, and inbound PPPoED (note: pre-fix field names).
analyze_sweep.ps1 🔁 Batch analyzer that walks each sweep pcap and dumps raw PPPoED frame data.
scanner_selfcheck.ps1 🔁 Early self-check of the scanner/analyzer chain (superseded by deep_frame_probe + positive_control).
b2dump.ps1 🧪 Dumps every frame in a small capture with type/proto/src/dst/vlan.
diag2.ps1 🧪 Lists all frames with eth.type + src/dst + protocol (quick triage).
montags.ps1 🧪 Lists all frames by direction/vlan/ethertype and isolates frames not sourced from our MAC (i.e. genuinely inbound).
inspect_inbound.ps1 🧪 Focuses on inbound PPPoED frames (not our MAC) in a capture.
ipv6_detail.ps1 🧪 Inspects IPv6 source + ICMPv6 types (rules out IPv6 RA noise being mistaken for a reply).
framedump.ps1 🧪 Dumps the modem web-UI frame.asp menu items (targets/links) — web-UI mapping helper.
diag1.ps1 🧪 Starts a background capture for ad-hoc diagnosis.

9.5 · Telnet engineering-CLI access

Tool What it does
telnet_login2.ps1 Raw-TCP telnet login with IAC negotiation + credential fallback list; enumerates the CLI (?) and probes su. Read-only.
telnet_run.ps1 Generic command runner: login → su (SU_WAP>) → run commands from a -CmdFile → print output. Creds read from an external file.
telnet_probe.ps1 🔁 First telnet probe (raw socket, no telnet.exe); logs in and issues only safe read/help commands to learn the CLI. Superseded by telnet_login2 + telnet_run.

9.6 · Modem web-UI probing (read-only HTTP)

All of these authenticate to the HG8310M web UI (GetRandCount.asp token → base64 password → POST /login.cgi, using the working web-admin account) and then GET status pages. They are read-only; the shared login pattern lives in hwlib.ps1.

Tool What it does
hwlib.ps1 Shared library: HW-Connect (login, session in $global:HWS) + HW-Get (authenticated GET). Dot-sourced by the probes below.
modem_login_test.ps1 Verifies the web-UI login flow works and reports the result.
modem_inline.ps1 Self-contained inline login (documents the exact token/base64/cookie/POST sequence).
modemping.ps1 Times ICMP ping + raw HTTP GET latency to the modem.
modemretry.ps1 Waits for the web server to recover from locked sessions, then retries TCP 80 + a fresh GET.
modemstat.ps1 Logs in and pulls general modem status pages.
probe_modem.ps1 Tests which device/optic/eth info pages actually return content (page discovery).
d2.ps1 🧪 Scrapes index.asp for frames/iframes and all .asp/.html/.cgi links (site-map).
d3.ps1 🧪 Login + page-fetch iteration variant.
d4.ps1 🧪 Login + targeted page-fetch variant.
discover.ps1 🧪 Extracts the frame/menu structure from index.asp.
menuscan.ps1 🧪 Enumerates the web-UI menu tree after login.
framefull.ps1 🧪 Lists all .asp paths referenced anywhere in frame.asp.
wanpages.ps1 🧪 Fetches candidate WAN/PPPoE config pages.
wancheck.ps1 🧪 Checks the WAN configuration page(s) for existing PPPoE/bridge setup.
wan_deep_check.ps1 🧪 Deeper WAN-layer inspection via the web UI.
wan_urls_probe.ps1 Probes ~24 standard Huawei WAN/PPPoE/VLAN config-page paths across firmware variants and reports which actually EXIST (HTTP 200 + non-trivial length). Confirms this pure-bridge unit exposes no WAN service page.
read_reset_page.ps1 🧪 Reads reset.asp to enumerate reboot/restore-default forms & CGI actions (read-only; nothing triggered).
gpon_auth_probe.ps1 Read-only probe for a GPON auth-config page (SN / PLOAM / LOID / equipment-id). Result: no such page in this web UI; get.cgi returns a stub.
modem_config_backup.ps1 Full config backup downloader: logs in and pulls the encrypted hw_ctree.xml (tries several backup endpoints), saving a timestamped copy. Read-only — intended to back up before any future change.

9.7 · Optical / SN / device-info readers

Tool What it does
read_sn_optic.ps1 Reads device info (SN / model / versions) from deviceinfo.asp and optical info (Tx/Rx power, temperature, bias) from opticinfo.asp.
optic.ps1 🔁 Pulls the optic-info page and prints Tx/Rx power.
optic2.ps1 🔁 Optic reader variant (works around routing to reach the modem directly).
opticfind.ps1 🔁 Locates the correct optic-info page across firmware layouts.
optread.ps1 🔁 Reads and parses optical power values.
optfinal.ps1 🔁 Final consolidated optic reader.
fulloptic.ps1 🔁 Full optical dump plus all index.asp hrefs/InitValue pages.
deepoptic.ps1 🔁 Robust optic reader with login retries.
sninfo.ps1 🔁 Extracts SN / serial / equipment-id tokens from device-info pages.
ponstate.ps1 Reads PON/registration state indicators from the web UI.
linkstate.ps1 🔁 Reads optical LinkStatus / LinkTime from the web UI.
dump.ps1 🧪 Logs in and grabs the optic-info page in one shot (quick dump).
extract_vals.ps1 🧪 Extracts interesting JS variable assignments (values) from web pages.
media_check.ps1 🧪 Polls the PPPoE-VLAN827 vNIC media/connection state over time after setting VLAN 827.

9.8 · Host state, routing & restore

Tool What it does
backup.ps1 Saves the current network state (adapters, vSwitch, advanced props, RegVlanid) so every change is revertible.
state.ps1 Quick state: which iface holds 192.168.100.2, plus a modem ping.
state_now.ps1 Snapshot of vSwitch, ManagementOS vNIC VLAN mode, and all net adapters.
verify_state.ps1 Verifies the management path (Wi-Fi/Tailscale up) + vSwitch/vNIC VLAN state — the pre/post-change safety check.
verify2.ps1 Confirms SSH/host alive + management adapters up.
chk.ps1 Confirms tagging works: physical NIC IP gone, VLAN-827 vNIC present, untagged modem unreachable from tagged vNIC.
routes.ps1 Lists all non-loopback IPv4 interfaces and the route to 192.168.100.1.
fixroute.ps1 Adds a low-metric on-link route for the modem subnet via the VLAN-827 vNIC.
xray.ps1 Inspects the xray_tun adapter routes/metrics (a co-existing tunnel on the host).
do_reboot.ps1 ⚠️ Ensures untagged (panel reachable after boot) then reboots the modem via the web UI. The only state-changing modem action; used deliberately, with the management path preserved.
finalize.ps1 Restore-to-stable + writes the "go-live" script (see §9.0).

9.9 · Raw-frame injection primitives (C# / wpcap)

Tool What it does
poc_send.ps1 Proof-of-concept C# P/Invoke to wpcap.dll (pcap_open_live / pcap_sendpacket / pcap_close) that sends one raw 802.1Q-tagged PADI frame — the injection primitive the scanner is built on.
poc_verify.ps1 Sends a frame and verifies it was captured — proves the inject+sniff loop on MonTrunk works end-to-end.

9.10 · Shell helpers (run over the reverse-SSH tunnel)

These Bash helpers drive the Windows host from the Ubuntu server. They read credentials from local *.env files at runtime (via awk) and never hard-code or print them.

Tool What it does
win.sh Runs a single command on the Windows host over the reverse-SSH tunnel (sshpass + port 2222).
ps.sh Executes a PowerShell script from stdin on Windows, base64-encoding it (UTF-16LE -EncodedCommand) to avoid escaping issues.
runfile.sh scp's a local .ps1 to the Windows host and executes it — the reliable path for long scripts (used for the scanner/analyzer).
putcreds.sh Writes the PPPoE credential drop-file on Windows via stdin (never on the command line).

10 · Telnet Command Lists

Read-only command lists fed to telnet_run.ps1 (-CmdFile). They target the HG8310M engineer shell (SU_WAP>).

List Purpose / key commands
tcmds_read.txt Core read-outs: display version / inner version / sysinfo / sn / optic / onu info / access mode / optmode, get rogue status, display pppoe_em result, omcicmd alarm show, display pon statistics, display wan layer all, display startup info.
tcmds_omci.txt Minimal OMCI MIB dump: omcicmd mib show.
tcmds_omci2.txt Deeper OMCI MIB (mib show 0/256/266/268/281), show flow/qos, pm show, display oam l2shell ethvlan, display flow.
tcmds_flow.txt Flow / port / MAC counters: omcicmd show flow 0, display port statistics, display macaddress, display lanmac/wanmac/productmac, display onu info, display pon statistics.
tcmds_gem.txt GEM / T-CONT decisive probes: omcicmd show flow/qos all, get poncnt upgemport, display poncnt gemport upstatistic, display poncnt up/dnstatistic, display wan layer all, display access mode. This is where ERROR 0xfc000105 (no upstream data GEM) came from.

11 · Security & Privacy

This is a public repository. Before publishing, every secret was masked and verified absent from the working tree, the commit blobs, and the live remote:

Secret Handling
Web-admin password <REDACTED_WEB_PW> (30 files)
Telnet password(s) <REDACTED_TELNET_PW*>
GPON serial number <REDACTED_SN> / <REDACTED_SN_SUFFIX>
Host MAC address resolved at run time (see §8.1)
Public server IP / hostname <REDACTED_SERVER_IP> / <REDACTED_HOSTNAME>
Server-side secret file paths genericised

Audit correction. The first public revision claimed every MAC was masked, but the real host MAC survived as a raw byte array in four scripts ([byte[]]@(0x..,0x..,...) in vlan_scanner.ps1, positive_control.ps1, poc_send.ps1, poc_verify.ps1) and the Hyper-V vNIC MAC appeared in five more, because the scrubbing pass only matched colon-separated notation. Those literals have been removed — the MAC is now discovered from the adapter at run time, so the masking claim is finally accurate. A machine-specific Npcap device GUID was removed for the same reason.

  • Shell helpers read credentials from local *.env files at runtime; nothing is hard-coded.
  • Passwords come from environment variables (FV_MODEM_PW, FV_TELNET_CREDS) and a missing value raises an error — the scripts can no longer send a placeholder string as a password and mistake the failed login for an empty response.
  • .gitignore excludes all *.env, credential drop-files (pc.txt, mc*.txt), tokens, and packet captures (*.pcapng) so they can never be committed.
  • The GitHub token used to push is never stored in git config or committed — it is supplied only in the push URL at push time.

These scripts are diagnostic tools for the owner's own equipment. The default credentials they reference are widely documented vendor defaults; they are masked here purely as good hygiene for a public repo.

11.1 · Static-analysis & portability pass

The tree is checked with PSScriptAnalyzer 1.25.0 plus an AST parse of every script. The pass below was mechanical but verified, not assumed: each rewrite was applied by walking the PowerShell token stream (never a blind regex), so words such as Select inside comments, strings, here-strings, hash keys and property accesses were provably left alone, and every file was byte-compared afterwards.

Finding Before After Why it mattered
Total findings 150 36 see the accounting of the remainder below
PSAvoidUsingComputerNameHardcoded (Error) 4 0 the modem IP was baked into Test-Connection/Test-NetConnection
PSAvoidUsingCmdletAliases 71 → really 73 0 Select/Where/Sort are not defined in every host; the expanded names always are
PSUseBOMForUnicodeEncodedFile 24 0 the Persian banners rendered as mojibake under Windows PowerShell 5.1, which reads a BOM-less file with the ANSI code page
PSUseDeclaredVarsMoreThanAssignments 13 0 two of these were real bugs, see below
PSAvoidUsingEmptyCatchBlock 2 0 the swallowed errors are intentional and are now documented as such

The analyzer itself undercounts, so it was not trusted either. Run on Linux, PSScriptAnalyzer reported 71 aliases; the true figure is 73. Sort, Group, cat, ls, sleep and friends are aliases only on Windows PowerShell hosts, so on Linux the rule simply cannot see them (routes.ps1 and xray.ps1 each hid one Sort). The counts above were therefore re-derived independently by walking the AST token stream and matching on TokenFlags.CommandName — which is host-independent — and that count is what the table reports.

Two of the "unused variable" findings were not cosmetic at all:

  • The retry result was discarded. In run_311/312/827/unt.ps1 and vsweep.ps1 a failed dial triggered a second attempt into $d2, but the report printed the first attempt's $r1, so a successful retry was reported as a failure. $r1 is now recomputed from the retry.
  • A second dial was never reported. scenarioB2.ps1 dialled twice on purpose but only ever printed dial1; it now prints both.

The modem address is no longer hard-coded anywhere: all 87 occurrences across 46 files now resolve through Get-FvModemIp (FV_MODEM_IP), leaving only the single default inside fvconfig.ps1.

The admin account had the same defect, and it was found by the new commit hook rather than by reading the code. FV_MODEM_USER was advertised in §8.1 as an override, but only 3 of the 33 scripts actually called Get-FvModemUser; the other 30 posted a literal UserName=telecomadmin, so exporting the variable changed nothing — a silent no-op of exactly the same shape as the modem-IP bug. All 27 login bodies now interpolate $(Get-FvModemUser). Every one of those files already dot-sourced fvconfig.ps1, which was verified before the change, and the override was then confirmed end-to-end (default → rootadmin@isp → default).

A trap worth recording. PowerShell variable names are case-insensitive, so $modemIp and $ModemIP are the same variable. Adding a naive $modemIp = Get-FvModemIp line to the telnet scripts silently overwrote the caller's -ModemIP argument. Those scripts now use if (-not $ModemIP) { $ModemIP = Get-FvModemIp }, and the precedence (explicit argument → FV_MODEM_IP → default) is covered by a test.

The 36 findings that remain — and why each one stays

These are not a backlog. Every one was read at its call site and left in place on purpose, because the mechanical "fix" would have made the code worse.

Rule Left Where Why it stays
PSAvoidUsingPositionalParameters 21 all in fvselftest.ps1 Every hit is a call to Assert-Equal, a local three-parameter test helper defined in that same file (-Name -Actual -Expected) — not a cmdlet. Assert-Equal 'PADI' (Count-Filter …) 1 is the readable form; naming all three would bury the assertions in noise.
PSUseShouldProcessForStateChangingFunctions 5 New-TestFrame, New-PADI ×3, New-PPPoEDisc The rule fires on the verb, not on behaviour. These are pure functions: they write bytes into a MemoryStream and return a byte[]. They touch no file, registry, service or NIC, so -WhatIf would be meaningless. (The functions that do change state — reboot, VLAN set — already have ShouldProcess; see §8.1.)
PSAvoidGlobalVars 4 $global:base, $global:HWS (hwlib.ps1), $global:S (read_reset_page.ps1) Cross-scope reuse is the feature. hwlib.ps1 is dot-sourced by five probes that must share one authenticated modem session; $global:S deliberately leaves the logged-in session in the caller's shell for interactive follow-up. Scoping them to $script: would break the dot-source contract.
PSUseApprovedVerbs 4 HW-Connect, HW-Get, HW-Try, Count-Filter Renaming is a breaking change to a published API: the HW-* helpers are documented in §10 of this file and called from six scripts. Count-Filter is a private one-liner inside the self-test. No approved verb conveys "HuaweiWeb-authenticated GET".
PSUseSingularNouns 2 Convert-FvMacToBytes, Get-FvSrcMacBytes The plural is factually correct — both return a 6-element byte[], and the singular …ToByte would actively mislead a reader into expecting one byte. Renaming would also break four call sites.

In short: the 4 Errors and every finding that indicated a real defect were fixed; what remains is 36 style opinions that conflict with either correctness or a documented interface, and are recorded here rather than silently churned.

11.2 · Commit-time guard against re-leaking live values

Removing the leaked values once is not enough — nothing stopped them coming back. .githooks/pre-commit scans only the staged content and refuses the commit if a live value reappears. Enable it once per clone:

git config core.hooksPath .githooks

It blocks a hard-coded modem IP, an Npcap adapter GUID, any bare GUID, a literal password, a real MAC address, a literal telecomadmin, an inlined PPPoE subscriber account, and any *.env file. It deliberately allows the Get-Fv* indirections, the single default inside fvconfig.ps1, the documentation placeholders (aa:bb:cc:dd:ee:ff, 02:00:00:00:00:01, ff:ff:ff:ff:ff:ff), $(Get-FvModemUser) subexpressions, and descriptive comments. Markdown is exempt from the "which address/account is named" rules only — this report is about this equipment, so the prose may name them — but a GUID, MAC or password is still blocked in Markdown too.

The hook is a security control, so it was tested like one rather than assumed to work: 13 hostile inputs were all caught and 9 legitimate ones all passed, with zero false positives. Two real defects in the hook itself were found and fixed that way — grep -n prefixes each candidate with <lineno>:, which silently defeated a ^\s*# comment allow-list, and the hook flagged its own pattern table until .githooks/ was exempted.

--no-verify bypasses the hook. That is intentional for a genuine new placeholder, but it means the hook is a safety net, not a boundary: the real protection is that no script needs a live value any more.


12 · Status & Remaining Work

Aspect Result
VLAN result All 4094 VLANs swept → 0 PADO (verified with a positive control).
PPPoE result Still failing — blocked upstream at the PON layer.
Internet result Not achievable from the customer side alone.
Root cause OLT-side data-service provisioning gap (no upstream GEM).
Firmware Cannot fix this class of fault (service is OLT-pushed via OMCI).

Remaining / next steps

  • ISP action: provision the data-service GEM/T-CONT/VLAN/bridge for this ONU (see §7 and the hand-off doc docs/ISP_HANDOFF.md).
  • Full config backup of the modem before any future change (tool ready: modem_config_backup.ps1).
  • Firmware upgrade for stability — with the honest caveat that it will not create the missing upstream service.
  • Go-live: once the ISP provisions the service, run the script emitted by finalize.ps1 to re-tag VLAN 827 and dial.

13 · FAQ — Common PPPoE / GPON Questions

What causes PPPoE error 651 on a fiber (GPON) connection?

Windows error 651 means the PPPoE client sent a PADI (PPPoE Active Discovery Initiation) broadcast and never received a PADO offer. It is a symptom, not a cause. The real cause is anywhere along this chain:

  1. Wrong or missing 802.1Q VLAN tag — the ISP expects tagged frames and you are sending untagged (or vice-versa). Sweep with vlan_scanner.ps1.
  2. Blind capture pipeline — you are getting a PADO but your analyzer/filter is not seeing it. Always run fvselftest.ps1 first.
  3. Wrong network adapter — frames leave a different NIC than the one you capture on. Use whichnic.ps1.
  4. No upstream data path at the PON layer — the ONU is registered but has no data-service GEM port / T-CONT, so the PADI is discarded before it reaches the BRAS. This was the cause in this repository's case — see §6.
  5. Genuinely wrong credentials — but note this produces a different failure (you would get PADO/PADS and then fail in PPP authentication, typically error 691, not 651).
My ONU is in state O5 with good optical power, so why is there no internet?

O5 only proves the ONU completed PLOAM ranging and is operational at the transmission layer. It says nothing about whether a service was provisioned.

For traffic to flow, the OLT must additionally push, via OMCI:

  • a T-CONT (upstream bandwidth allocation),
  • a GEM port mapped to that T-CONT for user data,
  • a service VLAN and a bridge/mapper binding the GEM to the UNI port.

If the operator registered your ONU (giving you O5 and an ONU-ID) but never completed the data-service half, you get exactly this signature: perfect optics, healthy PON state, and zero traffic. See §5 and §6.

How do I find out which VLAN ID my ISP uses for PPPoE?

Sweep it empirically. The toolkit sends a tagged PADI on every VLAN ID from 1 to 4094 and watches for a PADO:

pwsh -File tools/fvselftest.ps1     # 1. prove the analyzer is NOT blind
pwsh -File tools/vlan_scanner.ps1   # 2. sweep 1-4094

Each probe stamps a Host-Uniq tag of "VL" + <vlan-hi> + <vlan-lo> (VLAN 827 → 564c033b), so a returning PADO tells you exactly which VLAN answered — even if several replies arrive out of order.

⚠️ A silent sweep only means something if your positive control passed. That is why the self-test exists and why it must be run first.

Can a firmware upgrade on my ONT fix this?

No — not for this class of fault. The missing GEM port / T-CONT / service VLAN is pushed to the ONU by the OLT over OMCI. It is operator-side configuration state, not ONT-side firmware. Reflashing, factory-resetting, or replacing the ONT cannot create a service the OLT never provisioned.

Is this only useful for Huawei HG8310M?

No. The PPPoE Discovery and 802.1Q layers are vendor-neutral — the VLAN sweep, frame builder and analyzer work against any PPPoE Access Concentrator.

Only the device-readout tools (HTTP endpoints and the telnet engineering CLI) are Huawei-specific, and they were developed against an HG8310M. Other Huawei ONTs (HG8010, HG8240, HG8245, HG8145) commonly expose similar endpoints, but this is not verified here — treat it as untested.

Will this reconfigure or damage my modem or my ISP's equipment?

The diagnostic tools are read-only: they send standard PPPoE Discovery frames and read state over HTTP/telnet. They do not reprovision an OLT.

Two tools do change device state and are named accordingly — do_reboot.ps1 and the config-backup/restore paths. Review any such script before running it, and read SECURITY.md first.

⚠️ Only run this against a line you own or administer.

Where are the credentials stored? Is anything secret committed?

Nothing secret is committed, by design:

  • Every sensitive value is read from an FV_* environment variable through tools/fvconfig.ps1.
  • Get-FvModemPassword throws rather than falling back to a default.
  • A pre-commit leak guard blocks any commit containing a modem IP, adapter GUID, real MAC address, literal account name, inline PPPoE credential, or a *.env file.
  • Everything in the documentation is masked as <REDACTED_*>.

See §11 · Security & Privacy and SECURITY.md.


14 · Glossary

Term Meaning
PPPoE Point-to-Point Protocol over Ethernet — the dial-up-style session most DSL/fiber ISPs use to authenticate a subscriber.
PADI / PADO / PADR / PADS / PADT The five PPPoE Discovery packet types (codes 0x09, 0x07, 0x19, 0x65, 0xa7). The client broadcasts PADI; a server must answer PADO.
Error 651 Windows dial-up error meaning "the modem reported an error" — in practice, no PADO was received.
802.1Q / VLAN tag A 4-byte Ethernet header (TPID 0x8100) carrying a 12-bit VLAN ID (1–4094). Many ISPs require a specific ID.
GPON Gigabit Passive Optical Network — the fiber access technology (ITU-T G.984).
ONT / ONU Optical Network Terminal / Unit — the fiber modem at the subscriber's premises.
OLT Optical Line Terminal — the operator-side device that controls every ONU on the PON.
PLOAM state O1–O5 The ONU activation state machine. O5 = operational, i.e. ranged and running — but not necessarily provisioned with a data service.
OMCI ONU Management and Control Interface — the protocol the OLT uses to configure the ONU. Service config is pushed down, never set locally.
GEM port GPON Encapsulation Method port — a logical channel carrying user traffic. No GEM port ⇒ no data path.
T-CONT Transmission Container — the upstream bandwidth allocation an ONU needs in order to send.
BRAS / BNG Broadband Remote Access Server — the box that actually terminates PPPoE and answers PADO.
Npcap The Windows packet-capture driver used to send/receive raw frames.
Host-Uniq A PPPoE tag echoed back by the server; this toolkit encodes the probed VLAN ID into it to correlate replies.

15 · Contributing, License & Citation

🤝 Contributing See CONTRIBUTING.md. The rule is claims must be provable, not plausible — bring a packet capture or a CLI transcript.
🐛 Report a bug / get help Use the issue templates. Redact all secrets first.
🔒 Security See SECURITY.md. Please report vulnerabilities privately.
📜 License MIT — free to use, modify and distribute.
🤗 Code of Conduct CODE_OF_CONDUCT.md
📚 Citation Machine-readable metadata in CITATION.cff. GitHub renders a "Cite this repository" button from it.

If this saved you time

If this toolkit or the case study helped you diagnose your own line, please ⭐ star the repository — it helps other people stuck on error 651 find it.

Keywords: PPPoE, PPPoE error 651, no PADO, PADI, PPPoE discovery, GPON, PON, ONU, ONT, OLT, OMCI, GEM port, T-CONT, 802.1Q, VLAN tagging, VLAN scanner, VLAN sweep, fiber troubleshooting, ISP provisioning, Huawei HG8310M, Npcap, tshark, Wireshark, packet analysis, PowerShell networking, network diagnostics.


Built with a bottom-up, evidence-first methodology — no guessing, every claim backed by a captured frame or a device-CLI readout.

⬆ Back to top

About

Fix PPPoE error 651 on GPON fiber: packet-level diagnostics. 116-tool read-only PowerShell toolkit (tshark + Npcap) sweeps 802.1Q VLAN 1-4094, decodes PADI/PADO/PADR/PADS discovery, reads ONU optical power, proves 'no PADO' is evidence, and pinpoints missing OLT-side OMCI GEM / T-CONT / VLAN provisioning on a Huawei HG8310M ONT. 22/22 self-test.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages