#ifndef GN_UNWRAP_H #define GN_UNWRAP_H #include #include #include // Inverse of geonet_wrap_shb() + dot11p_build_frame(): takes a raw 802.11 frame as delivered by // the WiFi driver's promiscuous RX callback and strips 802.11 header -> LLC/SNAP -> GeoNetworking // Basic/Common/extended header -> BTP-B header, leaving just the ITS payload (CAM UPER bytes) // and the sender's station id (GN_ADDR MID). // // Deliberately narrow, matching what this project actually transmits: only handles the // Single-Hop-Broadcast (TSB, HeaderType=5/Subtype=0) extended header shape, same as // geonet_wrap_shb() builds - the same "best-tested decode path" rationale documented there. // A real receiver would also need GeoBroadcast (HeaderType=4, used by DENM dissemination in // real deployments) and possibly Beacon/GeoUnicast - out of scope for now since nothing this // project talks to sends those. Extend header_type handling here if that changes. // // Only accepts BTP-B destination port 2001 (CAM, per ETSI TS 103 248) - other ports (e.g. 2002 // DENM) are silently rejected since the phone-side decoder only understands CAM right now. // // Returns true and fills *out_cam / *out_cam_len (pointing INTO the input frame buffer, not a // copy - valid only as long as `frame` is) if this was a well-formed, CAM-carrying SHB frame // this project can decode. Returns false otherwise (wrong ethertype, wrong header type, wrong // BTP port, truncated, or FCS/promiscuous-capture garbage - all common and expected on an // open-air capture, not logged as errors by the caller). // // No station id is extracted here on purpose: CAM's own ItsPduHeader.stationID (the first real // field inside the UPER payload this function hands back, per cam.c) is already the meaningful // application-level identifier - the Kotlin-side decoder reads it from there. The GN_ADDR MID // this frame also carries is a separate, link-layer-only pseudonym; extracting and forwarding // it too would just be a second, easily-confused "station id" for no benefit here. // // RSSI is NOT extracted here either - it comes from the promiscuous callback's own packet // metadata (wifi_pkt_rx_ctrl_t.rssi in main.c), not from anything inside the frame bytes. bool gn_unwrap_cam(const uint8_t *frame, int frame_len, const uint8_t **out_cam, int *out_cam_len); #endif