aboutsummaryrefslogtreecommitdiffhomepage
path: root/content/posts/cellbroadcast/index.md
diff options
context:
space:
mode:
Diffstat (limited to 'content/posts/cellbroadcast/index.md')
-rw-r--r--content/posts/cellbroadcast/index.md283
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