Add utility to parse 3G get response data
authorDenis Kenzior <denkenz@gmail.com>
Fri, 2 Oct 2009 22:47:44 +0000 (17:47 -0500)
committerDenis Kenzior <denkenz@gmail.com>
Fri, 2 Oct 2009 23:25:56 +0000 (18:25 -0500)
Based on ETSI 102.221

src/simutil.c
src/simutil.h

index 2b5db2a..c294489 100644 (file)
@@ -574,6 +574,115 @@ struct sim_ef_info *sim_ef_db_lookup(unsigned short id)
        return result;
 }
 
+gboolean sim_parse_3G_get_response(unsigned char *data, int len,
+                                       int *file_len, int *record_len,
+                                       int *structure, unsigned char *access,
+                                       unsigned short *efid)
+{
+       const unsigned char *fcp;
+       int fcp_length;
+       const unsigned char *tlv;
+       int tlv_length;
+       int i;
+       int flen, rlen, str;
+       unsigned short id;
+       unsigned char acc[3];
+       struct sim_ef_info *info;
+
+       fcp = ber_tlv_find_by_tag(data, 0x62, len, &fcp_length);
+
+       if (fcp == NULL)
+               return FALSE;
+
+       /* Find the file size tag 0x80 according to
+        * ETSI 102.221 Section 11.1.1.3.2 */
+       tlv = ber_tlv_find_by_tag(fcp, 0x80, fcp_length, &tlv_length);
+
+       if (!tlv || tlv_length < 2)
+               return FALSE;
+
+       flen = tlv[0];
+       for (i = 1; i < tlv_length; i++)
+               flen = (flen << 8) | tlv[i];
+
+       tlv = ber_tlv_find_by_tag(fcp, 0x83, fcp_length, &tlv_length);
+
+       if (!tlv || tlv_length != 2)
+               return FALSE;
+
+       id = (tlv[0] << 8) | tlv[1];
+
+       tlv = ber_tlv_find_by_tag(fcp, 0x82, fcp_length, &tlv_length);
+
+       if (!tlv || (tlv_length != 2 && tlv_length != 5))
+               return FALSE;
+
+       if (tlv[1] != 0x21)
+               return FALSE;
+
+       switch (tlv[0] & 0x3) {
+       case 1: /* Transparent */
+               str = 0x00;
+               break;
+       case 2: /* Linear Fixed */
+               str = 0x01;
+               break;
+       case 6: /* Cyclic */
+               str = 0x03;
+               break;
+       default:
+               return FALSE;
+       };
+
+       /* For cyclic or linear fixed we need record size & num records */
+       if (str != 0x00 && tlv_length != 5)
+               return FALSE;
+
+       /* strictly speaking the record length is 16 bit, but the valid
+        * range is 0x01 to 0xFF according to 102.221 */
+       if (str != 0x00)
+               rlen = tlv[3];
+       else
+               rlen = 0;
+
+       /* The 3G response data contains references to EFarr which actually
+        * contains the security attributes.  These are usually not carried
+        * along with the response data unlike in 2G.  Instead of querying
+        * this, we simply look it up in our database.  We fudge it somewhat
+        * and guess if the file isn't found.
+        */
+       info = sim_ef_db_lookup(id);
+
+       if (str == 0x03)
+               acc[1] = 0x1f;
+       else
+               acc[1] = 0xff;
+
+       acc[2] = 0x44;
+
+       if (!info)
+               acc[0] = 0x11;
+       else
+               acc[0] = (info->perm_read << 4) | info->perm_update;
+
+       if (file_len)
+               *file_len = flen;
+
+       if (record_len)
+               *record_len = rlen;
+
+       if (efid)
+               *efid = id;
+
+       if (structure)
+               *structure = str;
+
+       if (access)
+               memcpy(access, acc, 3);
+
+       return TRUE;
+}
+
 gboolean sim_parse_2G_get_response(unsigned char *response, int len,
                                        int *file_len, int *record_len,
                                        int *structure, unsigned char *access)
index 805ead0..843490f 100644 (file)
@@ -107,6 +107,11 @@ void sim_adn_build(unsigned char *data, int length,
 
 struct sim_ef_info *sim_ef_db_lookup(unsigned short efid);
 
+gboolean sim_parse_3G_get_response(unsigned char *data, int len,
+                                       int *file_len, int *record_len,
+                                       int *structure, unsigned char *access,
+                                       unsigned short *efid);
+
 gboolean sim_parse_2G_get_response(unsigned char *response, int len,
                                        int *file_len, int *record_len,
                                        int *structure, unsigned char *access);