aboutsummaryrefslogtreecommitdiff
path: root/fcp_parser.c
blob: 3067f942333e9808b0785cfd7978d5c2391a2675 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* ST-Ericsson U300 RIL
**
** Copyright (C) ST-Ericsson AB 2008-2010
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
**
** Based on reference-ril by The Android Open Source Project.
**
** Heavily modified for ST-Ericsson U300 modems.
** Author: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>
*/

#include <memory.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>

#define LOG_TAG "RILV"
#include <utils/Log.h>

#include "fcp_parser.h"
#include "misc.h"

int fcp_to_ts_51011(/*in*/ const char *stream, /*in*/ size_t len,
        /*out*/ struct ts_51011_921_resp *out)
{
    const char *end = &stream[len];
    struct tlv fcp;
    int ret = parseTlv(stream, end, &fcp);
    const char *what = NULL;
#define FCP_CVT_THROW(_ret, _what)  \
    do {                    \
        ret = _ret;         \
        what = _what;       \
        goto except;        \
    } while (0)

    if (ret < 0)
        FCP_CVT_THROW(ret, "ETSI TS 102 221, 11.1.1.3: FCP template TLV structure");
    if (fcp.tag != 0x62)
        FCP_CVT_THROW(-EINVAL, "ETSI TS 102 221, 11.1.1.3: FCP template tag");

    /*
     * NOTE: Following fields do not exist in FCP template:
     * - file_acc
     * - file_status
     */

    memset(out, 0, sizeof(*out));
    while (fcp.data < fcp.end) {
        unsigned char fdbyte;
        size_t property_size;
        struct tlv tlv;
        ret = parseTlv(fcp.data, end, &tlv);
        if (ret < 0)
            FCP_CVT_THROW(ret, "ETSI TS 102 221, 11.1.1.3: FCP property TLV structure");
        property_size = (tlv.end - tlv.data) / 2;

        switch (tlv.tag) {
            case 0x80: /* File size, ETSI TS 102 221, 11.1.1.4.1 */
                /* File size > 0xFFFF is not supported by ts_51011 */
                if (property_size != 2)
                    FCP_CVT_THROW(-ENOTSUP, "3GPP TS 51 011, 9.2.1: Unsupported file size");
                /* be16 on both sides */
                ((char*)&out->file_size)[0] = TLV_DATA(tlv, 0);
                ((char*)&out->file_size)[1] = TLV_DATA(tlv, 1);
                break;
            case 0x83: /* File identifier, ETSI TS 102 221, 11.1.1.4.4 */
                /* Sanity check */
                if (property_size != 2)
                    FCP_CVT_THROW(-EINVAL, "ETSI TS 102 221, 11.1.1.4.4: Invalid file identifier");
                /* be16 on both sides */
                ((char*)&out->file_id)[0] = TLV_DATA(tlv, 0);
                ((char*)&out->file_id)[1] = TLV_DATA(tlv, 1);
                break;
            case 0x82: /* File descriptior, ETSI TS 102 221, 11.1.1.4.3 */
                /* Sanity check */
                if (property_size < 2)
                    FCP_CVT_THROW(-EINVAL, "ETSI TS 102 221, 11.1.1.4.3: Invalid file descriptor");
                fdbyte = TLV_DATA(tlv, 0);
                /* ETSI TS 102 221, Table 11.5 for FCP fields */
                /* 3GPP TS 51 011, 9.2.1 and 9.3 for 'out' fields */
                if ((fdbyte & 0xBF) == 0x38) {
                    out->file_type = 2; /* DF of ADF */
                } else if ((fdbyte & 0xB0) == 0x00) {
                    out->file_type = 4; /* EF */
                    out->file_status = 1; /* Not invalidated */
                    ++out->data_size; /* file_structure field is valid */
                    if ((fdbyte & 0x07) == 0x01) {
                        out->file_structure = 0; /* Transparent */
                    } else {
                        if (property_size < 5)
                            FCP_CVT_THROW(-EINVAL, "ETSI TS 102 221, 11.1.1.4.3: Invalid non-transparent file descriptor");
                        ++out->data_size; /* record_size field is valid */
                        out->record_size = TLV_DATA(tlv, 3);
                        if ((fdbyte & 0x07) == 0x06) {
                            out->file_structure = 3; /* Cyclic */
                        } else if ((fdbyte & 0x07) == 0x02) {
                            out->file_structure = 1; /* Linear fixed */
                        } else {
                            FCP_CVT_THROW(-EINVAL, "ETSI TS 102 221, 11.1.1.4.3: Invalid file structure");
                        }
                    }
                } else {
                    out->file_type = 0; /* RFU */
                }
                break;
        }
        fcp.data = tlv.end;
    }

 finally:
    return ret;

 except:
 #undef FCP_CVT_THROW
    LOGE("FCP to TS 510 11: Specification violation: %s.", what);
    goto finally;
}