/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * qmi-firmware-update -- Command line tool to update firmware in QMI devices * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Copyright (C) 2019 Zodiac Inflight Innovations * Copyright (C) 2019 Aleksander Morgado */ #include #include #include #include "qfu-firehose-message.h" /* NOTE: these parsers are NOT supposed to be general purpose parsers for the * firehose protocol message types, we're exclusively processing the messages * expected in the Sierra 9x50 firmware upgrade protocol, and therefore it's * assumed that using the regex matching approach is enough... */ #define FIREHOSE_MESSAGE_HEADER "\n\n" #define FIREHOSE_MESSAGE_TRAILER "\n\n\n" gsize qfu_firehose_message_build_ping (guint8 *buffer, gsize buffer_len) { g_snprintf ((gchar *)buffer, buffer_len, "%s" "" "%s", FIREHOSE_MESSAGE_HEADER, FIREHOSE_MESSAGE_TRAILER); return strlen ((gchar *)buffer); } gsize qfu_firehose_message_build_configure (guint8 *buffer, gsize buffer_len, guint max_payload_size_to_target_in_bytes) { g_snprintf ((gchar *)buffer, buffer_len, "%s" "" "%s", FIREHOSE_MESSAGE_HEADER, /* if not a specific value given, pass some placeholder big value; we expect the modem * to return a NAK with the correct value to use after that. */ max_payload_size_to_target_in_bytes ? max_payload_size_to_target_in_bytes : 1048576, FIREHOSE_MESSAGE_TRAILER); return strlen ((gchar *)buffer); } gsize qfu_firehose_message_build_get_storage_info (guint8 *buffer, gsize buffer_len) { g_snprintf ((gchar *)buffer, buffer_len, "%s" "" "%s", FIREHOSE_MESSAGE_HEADER, FIREHOSE_MESSAGE_TRAILER); return strlen ((gchar *)buffer); } gsize qfu_firehose_message_build_program (guint8 *buffer, gsize buffer_len, guint pages_per_block, guint sector_size_in_bytes, guint num_partition_sectors) { g_snprintf ((gchar *)buffer, buffer_len, "%s" "" "%s", FIREHOSE_MESSAGE_HEADER, pages_per_block, sector_size_in_bytes, num_partition_sectors, FIREHOSE_MESSAGE_TRAILER); return strlen ((gchar *)buffer); } gsize qfu_firehose_message_build_reset (guint8 *buffer, gsize buffer_len) { g_snprintf ((gchar *)buffer, buffer_len, "%s" "" "%s", FIREHOSE_MESSAGE_HEADER, FIREHOSE_MESSAGE_TRAILER); return strlen ((gchar *)buffer); } gboolean qfu_firehose_message_parse_response_ack (const gchar *rsp, gchar **value, gchar **rawmode) { GRegex *r; GMatchInfo *match_info = NULL; gboolean success = FALSE; /* * * * * */ r = g_regex_new ("\\s*\\s*", G_REGEX_RAW, 0, NULL); g_assert (r); if (!g_regex_match (r, rsp, 0, &match_info)) goto out; if (!g_match_info_matches (match_info)) goto out; if (value) *value = g_match_info_fetch (match_info, 1); if (rawmode) { if (g_match_info_get_match_count (match_info) > 2) *rawmode = g_match_info_fetch (match_info, 2); else *rawmode = NULL; } success = TRUE; out: if (match_info) g_match_info_unref (match_info); g_regex_unref (r); return success; } gboolean qfu_firehose_message_parse_log (const gchar *rsp, gchar **value) { GRegex *r; GMatchInfo *match_info = NULL; gboolean success = FALSE; /* * * * * */ r = g_regex_new ("\\s*\\s*", G_REGEX_RAW, 0, NULL); g_assert (r); if (!g_regex_match (r, rsp, 0, &match_info)) goto out; if (!g_match_info_matches (match_info)) goto out; if (value) *value = g_match_info_fetch (match_info, 1); success = TRUE; out: if (match_info) g_match_info_unref (match_info); g_regex_unref (r); return success; } gboolean qfu_firehose_message_parse_response_configure (const gchar *rsp, guint32 *max_payload_size_to_target_in_bytes) { GRegex *r; GMatchInfo *match_info = NULL; gboolean success = FALSE; /* * * * * */ r = g_regex_new ("\\s*\\s*", G_REGEX_RAW, 0, NULL); g_assert (r); if (!g_regex_match (r, rsp, 0, &match_info)) goto out; if (!g_match_info_matches (match_info)) goto out; if (max_payload_size_to_target_in_bytes) { gchar *aux; aux = g_match_info_fetch (match_info, 1); *max_payload_size_to_target_in_bytes = atoi (aux); g_free (aux); } success = TRUE; out: if (match_info) g_match_info_unref (match_info); g_regex_unref (r); return success; }