diff options
Diffstat (limited to 'content/posts/cellbroadcast/index.md')
-rw-r--r-- | content/posts/cellbroadcast/index.md | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/content/posts/cellbroadcast/index.md b/content/posts/cellbroadcast/index.md new file mode 100644 index 0000000..796b795 --- /dev/null +++ b/content/posts/cellbroadcast/index.md @@ -0,0 +1,283 @@ ++++ +authors = ["Guido Günther"] +title = "NL Cell Broadcast Test, ModemManager and Phosh" +date = "2023-12-10" +tags = [ "phosh", + "development", + ] +images = ["posts/cellbroadcast/cbm-lockscreen.jpg"] +series = [ + "Phosh internals" +] ++++ + +Cell broadcasts are a notification systems in mobile broadband networks +to inform all mobile devices (like smartphones) in a certain area +about security hazards like extreme weather or human made +disasters. It's somewhat similar to SMS but instead of being sent from +one device to another it's sent to all devices in that area. The messages +can be sent to all devices in a certain area or a whole country. + +In most countries there's every now and then an [announced test event][] +where a cell broadcast message is sent out although there's no +imminent threat. This was the case in the Netherlands on December 4th. + +Unfortunately we weren't in a position to receive and display +cell broadcast messages with Phosh on that date. This is due to the +component in the system responsible for interacting with the modem +(ModemManager) which handles voice calls, SMS, USSD, positioning +information, etc. just fine but not knowing anything about cell +broadcast messages yet. + +Due to some initial [debugging logs][] for [ModemManager][] from +an earlier cell broadcast test in Ontario (provided by Chris McGee) we +at least knew that "something" is received by the modem and (via QMI¹) +ends up in ModemManagers SMS code path where (as expected) parsing +fails. Is this the actual cell broadcast message already? + +# Parsing cell broadcast messages + +The [3GPP TS 23.041][] describes how cell broadcast messages (CBM) look +like. Roughly speaking it's some fixed length metadata and then the +actual message text. The maximum length of the message is 88 Bytes with +a 6 byte header and a maximum of 82 Bytes for the message itself. + +This is what the debug logs had: + +``` +<<<<<< value = 00:FF:FF:FF:FF:07:58:00:67:60:11:12:0F:16:54:74:7A:0E:4A:CF:41:61:10:BD:3C:A7:83:DE:66:10:1D:5D:06:3D:DD:F4:B0:3C:FD:06:05:D9:65:39:1D:24:2D:87:C9:79:D0:34:3F:A7:97:DB:2E:10:15:5D:96:97:41:E9:39:C8:FD:06:91:C3:EE:73:59:0E:A2:BF:41:F9:77:5D:0E:42:97:C3:6C:3A:1A:F4:96:83:E6:61:73:99:9E:07 +… +[1637171704.716921] [modem1] parsing PDU (0)... +[1637171704.716987] [modem1] This is a transfer-route message +[1637171704.717063] [modem1] error parsing PDU (0): Unhandled message type: 0x03 +``` + +A first try could be to take the last 82 bytes and assume each byte is an ASCII character. +That doesn't look too well though: + +> TtzJÏAa½<§Þf]=Ýô°<ýÙe9$-ÉyÐ4?§Û.]Aé9ÈýÃîsY¢¿Aùw]BÃl:�ôæas + +Let's try the GSM 7bit encoding (which is also used in SMS) on the same data. We could +do that with a small e.g. Python script (where a web search gives plenty of results). We +took a slightly different approach and added a small [test case][] to ModemManager (MM) that +would feed the data into MMs decoding function for SMS text: + +> This is a test of the Ontario Alert Ready System. There is no danger to your health or safety + +Bingo! This looks somewhat cut off at the end (no punctuation) but is readable text. +So now we knew what we receive is the actual CBM text. The 6 Bytes in +front of that is then likely the metadata and the 8 Bytes before that +are likely part of QMI. + +The metadata has multiples parts. The first two bytes is the serial number +that is used to uniquely identify a CBM. Part of the serial number +contains an update number (to indicate that a CBM is an update to previous CBM). + +The 3rd and 4th byte is the message identifier which indicates the source of the CBM. +This is country specific. In our case the `4370` means `Emergency Alert` in Canada. +The [AOSP][] has a list we can use to look that up. + +The 5th byte is the data coding scheme (how the text is encoded, in +our case GSM 7bit) and finally the 6th byte specifies how many parts a +message has and which part this is. With that information we can +extend our test case and see if the values make sense. And indeed our +CBM from Ontario above is the *first* part of a *six* part CBM so it's +not surprising that the text doesn't end properly. That's also why we +call the structure that stores the data ```MMCbmPart``` (the 3gpp +standard calls this a page). + +The nice thing about having this in form a of an executable test case is that we can easily +rerun it each time we make a change to the parsing code: + +``` +meson test -C _build test-cbs-part-3gpp --print-errorlogs +``` + +# Assembling cell broadcast messages and exposing them on DBus + +The other advantage is that we can check other CBMs easily that +somebody captured. We leveraged this for the NL test day on December +4th. Jan Vlug and Luca Weiss provided logs that contained three QMI +debug messages related to CBMs. Sticking the bytes from those into our +test parser we could see that the complete CBM should have 3 parts and +the parts we received had part number one to three. So decoding the +text from each part… + +- part 1 + +> NL-Alert 04-12-2023 12:00: TESTBERICHT. De overheid waarschuwt je tijdens noodsituaties via N + +- part 2 + +> L-Alert. Je leest dan wat je moet doen en waar je meer informatie kan vinden. *** TEST MESSAG + +- part 3 + +> E Netherlands Government Public Warning System. No action required. + + +…and concatenating it …we should get a complete message: + +> NL-Alert 04-12-2023 12:00: TESTBERICHT. De overheid waarschuwt je tijdens noodsituaties via NL-Alert. Je leest dan wat je moet doen en waar je meer informatie kan vinden. *** TEST MESSAGE Netherlands Government Public Warning System. No action required. + +Which was the case, yay! + +So it seems we're on the right track and can assemble these parts into +one message and expose it on DBus so applications like Chatty and +Phosh can make use of it. For that we [introduce][] a `MMBaseCbm` +that keeps track of the different parts and a `MMModemCellbroadcast` +that groups all CBMs received by a modem in the system into the +Modemmanager codebase. The code part isn't very exciting as it's +*very* similar to what is done for SMS. + +# Picking up the message out of the noise + +With the above we can parse the incoming message bits, assemble them and expose +them on DBus but we don't get the message bits out of the data the modem sends +to ModemManager. As mentioned above we were seeing those in the QMI stream already +but the logs provided from the NL test showed something else: + +``` +ModemManager[34764]: <debug> [1701687612.026406] [modem1/ttyUSB2/at] <-- '<CR><LF>+CBM: 88<CR><LF>46A0111305134E662BC82ECBE92018AD1593B56430D90C1493E960301D885A9C528545697288A4BA40C432E86D2FCBD1E53419740F87E5F331BA7EA783D465103DAD2697DD7390FBFD26CFD3F47A989E2ECF41F67418E404<CR><LF><CR><LF>+CBM: 88<CR><LF>46A011130523CC56905D96D35D206519C42E97E7741039EC06DDC37490BA0C6ABFCB7410F95D7683CA6ED03D1C9683D46550BB5C9683D26EF35BDE0ED3D365D03AEC06D9D36E72D9ED02A9542A10B538A5829AC5E9347804<CR><LF><CR><LF>+CBM: 65<CR><LF>46A0111305334590B34C4797E5ECB09B3C071DDFF6B2DCDD2EBBE920685DCC4E8F41D7B0DC9D769F41D3FC9C5E6EBB40CE37283CA6A7DF6E90BC1CAFA7E565B2AB<CR><LF>' +``` + +This means that the CBM parts not only end up in QMI but (at least for +the Librem 5 and Fair Phone 3) also end up in the serial communication +and are indicated by a `+CBM: <lengh>`. Equipped with that information +we can set up a (what ModemManager) calls an "unsolicited event +handler" that fetches the messages out of the serial stream for us and +passes it to the "message assembly" step. + +Now it would be nice to test if things actually work end to end. For that we +first wrote a [small tool][] called `mmcbmmonior` that listens +ModemManager's DBus interfaces to see if there are new cell broadcast +messages. Now the only thing left to do is wait for the next cell +broadcast test? + +We're basically adhering to [xkcd 303](https://xkcd.com/303/) here: +"I'm not slacking off, I'm waiting for a cell broadcast" …which could +be a rather long way off but there's a shortcut: As we're able to +leverage serial communication we can inject fake `+CBM` messages +into the serial stream at various places. One place is within +ModemManager itself where it parses the serial stream in +`parse_response_buffer`. Injecting it there (e.g. triggered by a +`SIGUSR1`) allows us to simulate pretty closely to what happens in a real situation +as all the code we added can't tell the difference. MM should then +grab the CBM parts out of the serial stream, assemble them and +expose an object on DBus. We can check that with `mmcbmmonior`: + +``` +$ _build/test/mmcbmmonitor +[/org/freedesktop/ModemManager1/CBM/0] new cbm: received + 4371: NL-Alert 04-12-2023 12:00: TESTBERICHT. De overheid waarschuwt je tijdens noodsituaties via NL-Alert. Je leest dan wat je moet doen en waar je meer informatie kan vinden. *** TEST MESSAGE Netherlands Government Public Warning System. No action required. +``` + +alternatively we can use `busctl` to see more details about the DBus property changes: + +``` +$ sudo busctl monitor org.freedesktop.ModemManager1 +Monitoring bus message stream. +‣ Type=signal Endian=l Flags=1 Version=1 Cookie=91 Timestamp="Sun 2023-12-10 12:12:13.372705 UTC" + Sender=:1.88 Path=/org/freedesktop/ModemManager1/Modem/0 Interface=org.freedesktop.DBus.Properties Member=PropertiesChanged + UniqueName=:1.88 + MESSAGE "sa{sv}as" { + STRING "org.freedesktop.ModemManager1.Modem.Cellbroadcast"; + ARRAY "{sv}" { + DICT_ENTRY "sv" { + STRING "Cellbroadcasts"; + VARIANT "ao" { + ARRAY "o" { + OBJECT_PATH "/org/freedesktop/ModemManager1/CBM/0"; + }; + }; + }; + }; + ARRAY "s" { + }; + }; + +‣ Type=signal Endian=l Flags=1 Version=1 Cookie=92 Timestamp="Sun 2023-12-10 12:12:13.388456 UTC" + Sender=:1.88 Path=/org/freedesktop/ModemManager1/Modem/0 Interface=org.freedesktop.ModemManager1.Modem.Cellbroadcast Member=Added + UniqueName=:1.88 + MESSAGE "o" { + OBJECT_PATH "/org/freedesktop/ModemManager1/CBM/0"; + }; + +‣ Type=signal Endian=l Flags=1 Version=1 Cookie=93 Timestamp="Sun 2023-12-10 12:12:13.389142 UTC" + Sender=:1.88 Path=/org/freedesktop/ModemManager1/CBM/0 Interface=org.freedesktop.DBus.Properties Member=PropertiesChanged + UniqueName=:1.88 + MESSAGE "sa{sv}as" { + STRING "org.freedesktop.ModemManager1.Cbm"; + ARRAY "{sv}" { + DICT_ENTRY "sv" { + STRING "State"; + VARIANT "u" { + UINT32 2; + }; + }; + DICT_ENTRY "sv" { + STRING "Text"; + VARIANT "s" { + STRING "NL-Alert 04-12-2023 12:00: TESTBERICHT. De overheid waarschuwt je tijdens noodsituaties via NL-Alert. Je leest dan wat je moet doen en waar je meer informatie kan vinden. *** TEST MESSAGE Netherlands Government Public Warning System. No action required."; + }; + }; + }; + ARRAY "s" { + }; + }; +``` + +# Informing the user + +With that sorted out the last bit left is alerting the user. As CBMs +are important we want them to be shown in Phosh even when the shell is locked +and the screen is off. This is how it currently looks: + +{{< video + src="cbm-lockscreen" + width="360px" + description="A cell broadcast message on Phosh's lockscreen" +>}} + +# Outlook + +As you can see from the links the code isn't merged yet. We can land +an [initial version][] in Phosh as soon as the ModemManager DBus +interface bits are in. From there on the Phosh and MM parts can +develop mostly independently. + +On the Phosh side we want to add proper queuing so multiple +cell broadcasts (or update to previous messages) are displayed one after +another. We also need to pick the right channel information (the title +of the dialog above) from the provided identifier, add a unique event to +[feedbackd][] and the sound theme to ensure the user gets alerted (for +the demo I've just`message-new-email`). Compared to what we have already +this is all pretty simple to add. + +On the MM side we want to add support for accepting messages via QMI +as well (for modems that don't use `+CBS`) and finally we want +[chatty][] to keep a history of received CBMs. + +How can you help? You can run the ModemManager from the [cellbroadcast merge request][] and +have `mmcbmmonior` running in the terminal. Whenever there's a CBM you should see it there. + +Together with the earlier addition of [emergency +calls](../emergency-calls/) this is one more step to make Phosh safe +to use for end users. + +¹: QMI is the (proprietary) way of Qualcomm processors (which are very, very common in modems) to talk to the +host processor. Another way to do that is serial communication (which will become useful below). Both are +(in our Linux phones) transported over USB. + +[3GPP TS 23.041]: https://www.etsi.org/deliver/etsi_ts/123000_123099/123041/15.02.00_60/ts_123041v150200p.pdf +[debugging logs]: https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/issues/253 +[ModemManager]: https://gitlab.freedesktop.org/mobile-broadband/ModemManager/ +[test case]: https://gitlab.freedesktop.org/agx/ModemManager/-/blob/cbm/src/tests/test-cbm-part.c +[AOSP]: https://cs.android.com/android/platform/superproject/main/+/main:packages/apps/CellBroadcastReceiver/tests/compliancetests/assets/emergency_alert_channels.json +[introduce]: https://gitlab.freedesktop.org/agx/ModemManager/-/blob/cbm/src/mm-base-cbm.c +[small tool]: https://gitlab.freedesktop.org/agx/ModemManager/-/blob/cbm/test/mmcbmmonitor.c +[chatty]: https://gitlab.gnome.org/World/Chatty/-/issues/513 +[cellbroadcast merge request]: https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1095 +[feedbackd]: https://source.puri.sm/Librem5/feedbackd +[initial version]: https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/1334 +[announced test event]: https://www.nl-alert.nl/testbericht |