@@ -21,6 +21,13 @@ struct call_forwarding_data {
struct qmi_service *voice;
};
+struct call_forwarding_info {
+ int8_t active;
+ uint8_t cls;
+ uint8_t len;
+ uint8_t number[];
+} __attribute__((__packed__));
+
struct call_forwarding_info_ext {
uint8_t active;
uint8_t cls;
@@ -31,7 +38,7 @@ struct call_forwarding_info_ext {
uint8_t plan;
uint8_t len;
uint8_t number[];
-};
+} __attribute__((__packed__));
static int forw_type_to_reason(int type)
{
@@ -56,7 +63,7 @@ static int forw_type_to_reason(int type)
static void set_fwd_cond(struct ofono_call_forwarding_condition *cond,
int status, int cls, int time, int type,
- uint8_t *number, uint8_t nlen)
+ const uint8_t *number, uint8_t nlen)
{
uint8_t maxlen = OFONO_MAX_PHONE_NUMBER_LENGTH;
@@ -76,56 +83,67 @@ static void query_cb(struct qmi_result *result, void *user_data)
{
struct cb_data *cbd = user_data;
ofono_call_forwarding_query_cb_t cb = cbd->cb;
- const uint8_t *p;
+ const void *p;
uint8_t num;
+ const uint8_t *end;
uint16_t length;
-
+ _auto_(l_free) struct ofono_call_forwarding_condition *list = NULL;
+ int i;
+ bool extended = false;
DBG("");
if (qmi_result_set_error(result, NULL))
goto error;
/*
- * we want extended info, because of the number type.
- * FIXME - shall we fallback to 0x10 if there is no extended info?
+ * we want extended info if any, because of the number type.
*/
p = qmi_result_get(result, 0x16, &length);
- if (p && length) {
- struct ofono_call_forwarding_condition *list;
- const uint8_t *end = p + length;
- int i;
+ if (p && length)
+ extended = true;
+ else
+ p = qmi_result_get(result, 0x10, &length);
- num = *p++;
+ if (!extended && (!p || !length))
+ goto error;
- list = l_new(struct ofono_call_forwarding_condition, num);
+ end = p + length;
+ num = l_get_u8(p++);
+ list = l_new(struct ofono_call_forwarding_condition, num);
- for (i = 0; i < num; i++) {
- struct call_forwarding_info_ext *info = (void *)p;
+ for (i = 0; i < num; i++) {
+ if (extended) {
+ const struct call_forwarding_info_ext *fi = p;
+ const uint8_t *iend = p + sizeof(*fi);
int type;
- /* do not try to access beyond buffer end */
- if (p + sizeof(*info) > end ||
- p + sizeof(*info) + info->len > end) {
- l_free(list);
+ if (iend > end || iend + fi->len > end)
goto error;
- }
- if (info->type == 1)
- type = OFONO_NUMBER_TYPE_INTERNATIONAL;
- else
- type = OFONO_NUMBER_TYPE_UNKNOWN;
+ type = fi->type == 1 ?
+ OFONO_NUMBER_TYPE_INTERNATIONAL :
+ OFONO_NUMBER_TYPE_UNKNOWN;
+ set_fwd_cond(&list[i], fi->active, fi->cls,
+ fi->time, type, fi->number, fi->len);
- set_fwd_cond(&list[i], info->active, info->cls,
- info->time, type, info->number,
- info->len);
- p += sizeof(*info) + info->len;
- }
+ p += sizeof(*fi) + fi->len;
+ } else {
+ const struct call_forwarding_info *fi = p;
+ const uint8_t *iend = p + sizeof(*fi) + 1;
- CALLBACK_WITH_SUCCESS(cb, num, list, cbd->data);
- l_free(list);
- return;
+ if (iend > end || iend + fi->len > end)
+ goto error;
+
+ p += sizeof(*fi) + fi->len;
+ set_fwd_cond(&list[i], fi->active, fi->cls,
+ l_get_u8(p++), OFONO_NUMBER_TYPE_UNKNOWN,
+ fi->number, fi->len);
+ }
}
+ CALLBACK_WITH_SUCCESS(cb, num, list, cbd->data);
+ return;
+
error:
CALLBACK_WITH_FAILURE(cb, 0, NULL, cbd->data);
}