Location: j1939/tp.go:90 (bamID), j1939/tp.go:100 (dtBaseID)
Finding: TP.CM (PGN 0xEC00, PF=0xEC=236) and TP.DT (PGN 0xEB00, PF=0xEB=235) are both PDU1-format PGNs, meaning the PS byte of the CAN ID carries a destination address rather than being folded into the PGN. For a BAM broadcast, SAE J1939-21 requires that destination byte to be the global address 0xFF. SendTP builds both the TP.CM and TP.DT arbitration IDs via EncodeID(f.Priority, pgnTPCM/pgnTPDT, b.src), and EncodeID's PDU1 branch (pgn.go:96) deliberately does not write the PS byte at all for PF<240 — so the PS byte comes out as 0x00, not 0xFF. A frame transmitted this way asks for destination address 0x00 rather than announcing itself as a broadcast, which a real J1939 ECU is not obligated to accept. This is invisible in go-CAN's own tests because SubscribeTP's in-process reassembler decodes the PGN via DecodeID and never inspects the PS/destination byte, so sender and receiver agree with each other even though neither matches the wire protocol.
Recommendation: OR the global address (uint32(BroadcastAddr) << 8) into bamID/dtBaseID explicitly, or route BAM ID construction through a TP-aware encode helper that always sets the destination byte for PDU1 TP frames.
Filed from the 2026-07-29 ecosystem audit register; independently re-verified against current HEAD before filing.
Location:
j1939/tp.go:90(bamID),j1939/tp.go:100(dtBaseID)Finding: TP.CM (PGN 0xEC00, PF=0xEC=236) and TP.DT (PGN 0xEB00, PF=0xEB=235) are both PDU1-format PGNs, meaning the PS byte of the CAN ID carries a destination address rather than being folded into the PGN. For a BAM broadcast, SAE J1939-21 requires that destination byte to be the global address 0xFF.
SendTPbuilds both the TP.CM and TP.DT arbitration IDs viaEncodeID(f.Priority, pgnTPCM/pgnTPDT, b.src), andEncodeID's PDU1 branch (pgn.go:96) deliberately does not write the PS byte at all for PF<240 — so the PS byte comes out as 0x00, not 0xFF. A frame transmitted this way asks for destination address 0x00 rather than announcing itself as a broadcast, which a real J1939 ECU is not obligated to accept. This is invisible in go-CAN's own tests becauseSubscribeTP's in-process reassembler decodes the PGN viaDecodeIDand never inspects the PS/destination byte, so sender and receiver agree with each other even though neither matches the wire protocol.Recommendation: OR the global address (
uint32(BroadcastAddr) << 8) intobamID/dtBaseIDexplicitly, or route BAM ID construction through a TP-aware encode helper that always sets the destination byte for PDU1 TP frames.Filed from the 2026-07-29 ecosystem audit register; independently re-verified against current HEAD before filing.