/pdu.c

http://datacard.googlecode.com/ · C · 806 lines · 496 code · 65 blank · 245 comment · 83 complexity · 2c292146530be56a633c257a4ec6f264 MD5 · raw file

  1. /*
  2. Copyright (C) 2010 bg <bg_one@mail.ru>
  3. */
  4. #ifdef HAVE_CONFIG_H
  5. #include <config.h>
  6. #endif /* HAVE_CONFIG_H */
  7. #include <errno.h> /* EINVAL ENOMEM E2BIG */
  8. #include "pdu.h"
  9. #include "helpers.h" /* dial_digit_code() */
  10. #include "char_conv.h" /* utf8_to_hexstr_ucs2() */
  11. /* SMS-SUBMIT format
  12. SCA 1..12 octet(s) Service Center Address information element
  13. octets
  14. 1 Length of Address (minimal 0)
  15. 2 Type of Address
  16. 3 12 Address
  17. PDU-type 1 octet Protocol Data Unit Type
  18. bits
  19. 1 0 MTI Message Type Indicator Parameter describing the message type 00 means SMS-DELIVER 01 means SMS-SUBMIT
  20. 0 0 SMS-DELIVER (SMSC ==> MS)
  21. or
  22. SMS-DELIVER REPORT (MS ==> SMSC, is generated automatically by the MOBILE, after receiving a SMS-DELIVER)
  23. 0 1 SMS-SUBMIT (MS ==> SMSC)
  24. or
  25. SMS-SUBMIT REPORT (SMSC ==> MS)
  26. 1 0 SMS-STATUS REPORT (SMSC ==> MS)
  27. or
  28. SMS-COMMAND (MS ==> SMSC)
  29. 1 1 Reserved
  30. 2 RD Reject Duplicate
  31. 0 Instruct the SMSC to accept an SMS-SUBMIT for an short message still
  32. held in the SMSC which has the same MR and
  33. 1 Instruct the SMSC to reject an SMS-SUBMIT for an short message still
  34. held in the SMSC which has the same MR and DA as a previosly
  35. submitted short message from the same OA.
  36. 4 3 VPF Validity Period Format Parameter indicating whether or not the VP field is present
  37. 0 0 VP field is not present
  38. 0 1 Reserved
  39. 1 0 VP field present an integer represented (relative)
  40. 1 1 VP field present an semi-octet represented (absolute)
  41. 5 SRR Status Report Request Parameter indicating if the MS has requested a status report
  42. 0 A status report is not requested
  43. 1 A status report is requested
  44. 6 UDHI User Data Header Indicator Parameter indicating that the UD field contains a header
  45. 0 The UD field contains only the short message
  46. 1 The beginning of the UD field contains a header in addition of the short message
  47. 7 RP Reply Path Parameter indicating that Reply Path exists
  48. 0 Reply Path parameter is not set in this PDU
  49. 1 Reply Path parameter is set in this PDU
  50. MR 1 octet Message Reference
  51. The MR field gives an integer (0..255) representation of a reference number of the SMSSUBMIT submitted to the SMSC by the MS.
  52. ! notice: at the MOBILE the MR is generated automatically, -anyway you have to generate it a possible entry is for example ”00H” !
  53. DA 2-12 octets Destination Address
  54. octets
  55. 1 Length of Address (of BCD digits!)
  56. 2 Type of Address
  57. 3 12 Address
  58. PID 1 octet Protocol Identifier
  59. The PID is the information element by which the Transport Layer either refers to the higher
  60. layer protocol being used, or indicates interworking with a certain type of telematic device.
  61. here are some examples of PID codings:
  62. 00H: The PDU has to be treat as a short message
  63. 41H: Replace Short Message Type1
  64. ....
  65. 47H: Replace Short Message Type7
  66. Another description:
  67. Bit7 bit6 (bit 7 = 0, bit 6 = 0)
  68. l 0 0 Assign bits 0..5, the values are defined as follows.
  69. l 1 0 Assign bits 0..5, the values are defined as follows.
  70. l 0 1 Retain
  71. l 1 1 Assign bits 0..5 for special use of SC
  72. Bit5 values:
  73. l 0: No interworking, but SME-to-SME protocol
  74. l 1: Telematic interworking (in this situation , value of bits4...0 is
  75. valid)
  76. Interface Description for HUAWEI EV-DO Data Card AT Commands
  77. All rights reserved Page 73 , Total 140
  78. Bit4...Bit0: telematic devices type identifier. If the value is 1 0 0 1 0, it
  79. indicates email. Other values are not supported currently.
  80. DCS 1 octet Data Coding Scheme
  81. VP 0,1,7 octet(s) Validity Period
  82. UDL 1 octet User Data Length
  83. UD 0-140 octets User Data
  84. */
  85. /* SMS-DELIVER format
  86. SCA 1..12 octet(s) Service Center Address information element
  87. octets
  88. 1 Length of Address (minimal 0)
  89. 2 Type of Address
  90. 3 12 Address
  91. PDU-type 1 octet Protocol Data Unit Type
  92. bits
  93. 1 0 MTI Message Type Indicator Parameter describing the message type 00 means SMS-DELIVER 01 means SMS-SUBMIT
  94. 0 0 SMS-DELIVER (SMSC ==> MS)
  95. or
  96. SMS-DELIVER REPORT (MS ==> SMSC, is generated automatically by the MOBILE, after receiving a SMS-DELIVER)
  97. 0 1 SMS-SUBMIT (MS ==> SMSC)
  98. or
  99. SMS-SUBMIT REPORT (SMSC ==> MS)
  100. 1 0 SMS-STATUS REPORT (SMSC ==> MS)
  101. or
  102. SMS-COMMAND (MS ==> SMSC)
  103. 1 1 Reserved
  104. 2 MMS More Messages to Send Parameter indicating whether or not there are more messages to send
  105. 0 More messages are waiting for the MS in the SMSC
  106. 1 No more messages are waiting for the MS in the SMSC
  107. 4 3 Reserved
  108. 5 SRI Status Report Indication Parameter indicating if the SME has requested a status report
  109. 0 A status report will not be returned to the SME
  110. 1 A status report will be returned to the SME
  111. 6 UDHI User Data Header Indicator Parameter indicating that the UD field contains a header
  112. 0 The UD field contains only the short message
  113. 1 The beginning of the UD field contains a header in addition of the short message
  114. 7 RP Reply Path Parameter indicating that Reply Path exists
  115. 0 Reply Path parameter is not set in this PDU
  116. 1 Reply Path parameter is set in this PDU
  117. OA 2-12 octets Originator Address
  118. octets
  119. 1 Length of Address (of BCD digits!)
  120. 2 Type of Address
  121. 3 12 Address
  122. PID 1 octet Protocol Identifier
  123. The PID is the information element by which the Transport Layer either refers to the higher
  124. layer protocol being used, or indicates interworking with a certain type of telematic device.
  125. here are some examples of PID codings:
  126. 00H: The PDU has to be treat as a short message
  127. 41H: Replace Short Message Type1
  128. ....
  129. 47H: Replace Short Message Type7
  130. Another description:
  131. Bit7 bit6 (bit 7 = 0, bit 6 = 0)
  132. l 0 0 Assign bits 0..5, the values are defined as follows.
  133. l 1 0 Assign bits 0..5, the values are defined as follows.
  134. l 0 1 Retain
  135. l 1 1 Assign bits 0..5 for special use of SC
  136. Bit5 values:
  137. l 0: No interworking, but SME-to-SME protocol
  138. l 1: Telematic interworking (in this situation , value of bits4...0 is
  139. valid)
  140. Interface Description for HUAWEI EV-DO Data Card AT Commands
  141. All rights reserved Page 73 , Total 140
  142. Bit4...Bit0: telematic devices type identifier. If the value is 1 0 0 1 0, it
  143. indicates email. Other values are not supported currently.
  144. DCS 1 octet Data Coding Scheme
  145. SCTS 7 octets Service Center Time Stamp
  146. UDL 1 octet User Data Length
  147. UD 0-140 octets User Data, may be prepended by User Data Header see UDHI flag
  148. octets
  149. 1 opt UDHL Total number of Octets in UDH
  150. ? IEIa
  151. ? IEIDLa
  152. ? IEIDa
  153. ? IEIb
  154. ...
  155. */
  156. #define NUMBER_TYPE_INTERNATIONAL 0x91
  157. /* Message Type Indicator Parameter */
  158. #define PDUTYPE_MTI_SHIFT 0
  159. #define PDUTYPE_MTI_SMS_DELIVER (0x00 << PDUTYPE_MTI_SHIFT)
  160. #define PDUTYPE_MTI_SMS_DELIVER_REPORT (0x00 << PDUTYPE_MTI_SHIFT)
  161. #define PDUTYPE_MTI_SMS_SUBMIT (0x01 << PDUTYPE_MTI_SHIFT)
  162. #define PDUTYPE_MTI_SMS_SUBMIT_REPORT (0x01 << PDUTYPE_MTI_SHIFT)
  163. #define PDUTYPE_MTI_SMS_STATUS_REPORT (0x02 << PDUTYPE_MTI_SHIFT)
  164. #define PDUTYPE_MTI_SMS_COMMAND (0x02 << PDUTYPE_MTI_SHIFT)
  165. #define PDUTYPE_MTI_RESERVED (0x03 << PDUTYPE_MTI_SHIFT)
  166. #define PDUTYPE_MTI_MASK (0x03 << PDUTYPE_MTI_SHIFT)
  167. #define PDUTYPE_MTI(pdutype) ((pdutype) & PDUTYPE_MTI_MASK)
  168. /* Reject Duplicate */
  169. #define PDUTYPE_RD_SHIFT 2
  170. #define PDUTYPE_RD_ACCEPT (0x00 << PDUTYPE_RD_SHIFT)
  171. #define PDUTYPE_RD_REJECT (0x01 << PDUTYPE_RD_SHIFT)
  172. /* Validity Period Format */
  173. #define PDUTYPE_VPF_SHIFT 3
  174. #define PDUTYPE_VPF_NOT_PRESENT (0x00 << PDUTYPE_VPF_SHIFT)
  175. #define PDUTYPE_VPF_RESERVED (0x01 << PDUTYPE_VPF_SHIFT)
  176. #define PDUTYPE_VPF_RELATIVE (0x02 << PDUTYPE_VPF_SHIFT)
  177. #define PDUTYPE_VPF_ABSOLUTE (0x03 << PDUTYPE_VPF_SHIFT)
  178. /* Status Report Request */
  179. #define PDUTYPE_SRR_SHIFT 5
  180. #define PDUTYPE_SRR_NOT_REQUESTED (0x00 << PDUTYPE_SRR_SHIFT)
  181. #define PDUTYPE_SRR_REQUESTED (0x01 << PDUTYPE_SRR_SHIFT)
  182. /* User Data Header Indicator */
  183. #define PDUTYPE_UDHI_SHIFT 6
  184. #define PDUTYPE_UDHI_NO_HEADER (0x00 << PDUTYPE_UDHI_SHIFT)
  185. #define PDUTYPE_UDHI_HAS_HEADER (0x01 << PDUTYPE_UDHI_SHIFT)
  186. #define PDUTYPE_UDHI_MASK (0x01 << PDUTYPE_UDHI_SHIFT)
  187. #define PDUTYPE_UDHI(pdutype) ((pdutype) & PDUTYPE_UDHI_MASK)
  188. /* eply Path Parameter */
  189. #define PDUTYPE_RP_SHIFT 7
  190. #define PDUTYPE_RP_IS_NOT_SET (0x00 << PDUTYPE_RP_SHIFT)
  191. #define PDUTYPE_RP_IS_SET (0x01 << PDUTYPE_RP_SHIFT)
  192. #define PDU_MESSAGE_REFERENCE 0x00 /* assigned by MS */
  193. #define PDU_PID_SMS 0x00 /* bit5 No interworking, but SME-to-SME protocol = SMS */
  194. #define PDU_PID_EMAIL 0x32 /* bit5 Telematic interworking, bits 4..0 0x 12 = email */
  195. /* DCS */
  196. /* bits 1..0 Class */
  197. #define PDU_DCS_CLASS_SHIFT 0
  198. #define PDU_DCS_CLASS0 (0x00 << PDU_DCS_CLASS_SHIFT) /* Class 0, provides display and responds SC */
  199. #define PDU_DCS_CLASS1 (0x01 << PDU_DCS_CLASS_SHIFT) /* Class 1, saves to MS (NV); or saves to the UIM card when MS is full */
  200. #define PDU_DCS_CLASS2 (0x02 << PDU_DCS_CLASS_SHIFT) /* Class 2, dedicated for the UIM card The storage status is reported to SC after storage If the UIM card is full, failure and reason are reported to SC */
  201. #define PDU_DCS_CLASS3 (0x03 << PDU_DCS_CLASS_SHIFT) /* Class 3, stored to TE, MS receives messages and does not sent to TE, but responds to SC */
  202. #define PDU_DCS_CLASS_MASK (0x03 << PDU_DCS_CLASS_SHIFT)
  203. #define PDU_DCS_CLASS(dcs) ((dcs) & PDU_DCS_CLASS_MASK)
  204. /* bits 3..2 Alpabet */
  205. #define PDU_DCS_ALPABET_SHIFT 2
  206. #define PDU_DCS_ALPABET_7BIT (0x00 << PDU_DCS_ALPABET_SHIFT)
  207. #define PDU_DCS_ALPABET_8BIT (0x01 << PDU_DCS_ALPABET_SHIFT)
  208. #define PDU_DCS_ALPABET_UCS2 (0x02 << PDU_DCS_ALPABET_SHIFT)
  209. #define PDU_DCS_ALPABET_MASK (0x03 << PDU_DCS_ALPABET_SHIFT)
  210. #define PDU_DCS_ALPABET(dcs) ((dcs) & PDU_DCS_ALPABET_MASK)
  211. /* bit 4 */
  212. #define PDU_DCS_BITS10_CTRL_SHIFT 4
  213. #define PDU_DCS_BITS10_RETAIN (0x00 << PDU_DCS_BIT10_CTRL_SHIFT)
  214. #define PDU_DCS_BITS10_INUSE (0x01 << PDU_DCS_BIT10_CTRL_SHIFT)
  215. #define PDU_DCS_BITS10_CTRL_MASK (0x01 << PDU_DCS_BIT10_CTRL_SHIFT)
  216. #define PDU_DCS_BITS10_CTRL(dcs) ((dcs) & PDU_DCS_BITS10_CTRL_MASK)
  217. /* bit 5 */
  218. #define PDU_DCS_COMPRESSION_SHIFT 5
  219. #define PDU_DCS_NOT_COMPESSED (0x00 << PDU_DCS_COMPRESSION_SHIFT)
  220. #define PDU_DCS_COMPESSED (0x01 << PDU_DCS_COMPRESSION_SHIFT)
  221. #define PDU_DCS_COMPRESSION_MASK (0x01 << PDU_DCS_COMPRESSION_SHIFT)
  222. #define PDU_DCS_COMPRESSION(dcs) ((dcs) & PDU_DCS_COMPRESSION_MASK)
  223. /* bit 7..6 */
  224. #define PDU_DCS_76_SHIFT 6
  225. #define PDU_DCS_76_00 (0x00 << PDU_DCS_76_SHIFT)
  226. #define PDU_DCS_76_MASK (0x03 << PDU_DCS_76_SHIFT)
  227. #define PDU_DCS_76(dcs) ((dcs) & PDU_DCS_76_MASK)
  228. #define ROUND_UP2(x) (((x) + 1) & (0xFFFFFFFF << 1))
  229. #define LENGTH2OCTETS(x) (((x) + 1)/2)
  230. #/* get digit code, 0 if invalid */
  231. EXPORT_DEF char pdu_digit2code(char digit)
  232. {
  233. switch(digit)
  234. {
  235. case '0':
  236. case '1':
  237. case '2':
  238. case '3':
  239. case '4':
  240. case '5':
  241. case '6':
  242. case '7':
  243. case '8':
  244. case '9':
  245. break;
  246. case '*':
  247. digit = 'A';
  248. break;
  249. case '#':
  250. digit = 'B';
  251. break;
  252. case 'a':
  253. case 'A':
  254. digit = 'C';
  255. break;
  256. case 'b':
  257. case 'B':
  258. digit = 'D';
  259. break;
  260. case 'c':
  261. case 'C':
  262. digit = 'E';
  263. break;
  264. default:
  265. return 0;
  266. }
  267. return digit;
  268. }
  269. #/* */
  270. static char pdu_code2digit(char code)
  271. {
  272. switch(code)
  273. {
  274. case '0':
  275. case '1':
  276. case '2':
  277. case '3':
  278. case '4':
  279. case '5':
  280. case '6':
  281. case '7':
  282. case '8':
  283. case '9':
  284. break;
  285. case 'a':
  286. case 'A':
  287. code = '*';
  288. break;
  289. case 'b':
  290. case 'B':
  291. code = '#';
  292. break;
  293. case 'c':
  294. case 'C':
  295. code = 'A';
  296. break;
  297. case 'd':
  298. case 'D':
  299. code = 'B';
  300. break;
  301. case 'e':
  302. case 'E':
  303. code = 'C';
  304. break;
  305. case 'F':
  306. return 0;
  307. default:
  308. return -1;
  309. }
  310. return code;
  311. }
  312. #/* convert minutes to relative VP value */
  313. static int pdu_relative_validity(unsigned minutes)
  314. {
  315. #define DIV_UP(x,y) (((x)+(y)-1)/(y))
  316. /*
  317. 0 ... 143 (vp + 1) * 5 minutes 5 ... 720 m = (vp + 1) * 5 m / 5 - 1 = vp
  318. 144...167 12 hours + (vp - 143) * 30 minutes 750 ... 1440 m = 720 + (vp - 143) * 30 (m - 720) / 30 + 143 = m / 30 + 119
  319. 168...196 (vp - 166) * 1 day 2880 ... 43200 m = (vp - 166) * 1440 (m / 1440) + 166
  320. 197...255 (vp - 192) * 1 week 50400 ...635040 m = (vp - 192) * 10080 (m / 10080) + 192
  321. */
  322. int validity;
  323. if(minutes <= 720)
  324. validity = DIV_UP(minutes, 5) - 1;
  325. else if(minutes <= 1440)
  326. validity = DIV_UP(minutes, 30) + 119;
  327. else if(minutes <= 43200)
  328. validity = DIV_UP(minutes, 1440) + 166;
  329. else if(minutes <= 635040)
  330. validity = DIV_UP(minutes, 10080) + 192;
  331. else
  332. validity = 0xFF;
  333. return validity;
  334. #undef DIV_UP
  335. }
  336. #/* convert 2 hex digits of PDU to byte, return < 0 on error */
  337. static int pdu_parse_byte(char ** digits2hex, size_t * length)
  338. {
  339. int res = -1;
  340. int res2;
  341. if(*length >= 2)
  342. {
  343. res = parse_hexdigit(*digits2hex[0]);
  344. if(res >= 0)
  345. {
  346. (*digits2hex)++;
  347. (*length)--;
  348. res2 = parse_hexdigit(*digits2hex[0]);
  349. if(res2 >= 0)
  350. {
  351. (*digits2hex)++;
  352. (*length)--;
  353. return (res << 4) | res2;
  354. }
  355. }
  356. }
  357. return res;
  358. }
  359. /*!
  360. * \brief Store number in PDU
  361. * \param buffer -- pointer to place where number will be stored, CALLER MUST be provide length + 2 bytes of buffer
  362. * \param number -- phone number w/o leading '+'
  363. * \param length -- length of number
  364. * \return number of bytes written to buffer
  365. */
  366. static int pdu_store_number(char* buffer, const char* number, unsigned length)
  367. {
  368. int i;
  369. for(i = 0; length > 1; length -=2, i +=2)
  370. {
  371. buffer[i] = pdu_digit2code(number[i + 1]);
  372. buffer[i + 1] = pdu_digit2code(number[i]);
  373. }
  374. if(length)
  375. {
  376. buffer[i] = 'F';
  377. buffer[i+1] = pdu_digit2code(number[i]);
  378. i += 2;
  379. }
  380. return i;
  381. }
  382. #/* reverse of pdu_store_number() */
  383. static int pdu_parse_number(char ** pdu, size_t * pdu_length, unsigned digits, int * toa, char * number, size_t num_len)
  384. {
  385. const char * begin;
  386. if(num_len < digits + 1)
  387. return -ENOMEM;
  388. begin = *pdu;
  389. *toa = pdu_parse_byte(pdu, pdu_length);
  390. if(*toa >= 0)
  391. {
  392. unsigned syms = ROUND_UP2(digits);
  393. if(syms <= *pdu_length)
  394. {
  395. char digit;
  396. if(*toa == NUMBER_TYPE_INTERNATIONAL)
  397. *number++ = '+';
  398. for(; syms > 0; syms -= 2, *pdu += 2, *pdu_length -= 2)
  399. {
  400. digit = pdu_code2digit(pdu[0][1]);
  401. if(digit <= 0)
  402. return -1;
  403. *number++ = digit;
  404. digit = pdu_code2digit(pdu[0][0]);
  405. if(digit < 0 || (digit == 0 && (syms != 2 || (digits & 0x1) == 0)))
  406. return -1;
  407. *number++ = digit;
  408. }
  409. if((digits & 0x1) == 0)
  410. *number = 0;
  411. return *pdu - begin;
  412. }
  413. }
  414. return -EINVAL;
  415. }
  416. #/* return bytes (not octets!) of pdu occupied by SCA or <0 on errors */
  417. static int pdu_parse_sca(char ** pdu, size_t * length)
  418. {
  419. /* get length of SCA field */
  420. int sca_len = pdu_parse_byte(pdu, length);
  421. if(sca_len >= 0)
  422. {
  423. sca_len *= 2;
  424. if((size_t)sca_len <= *length)
  425. {
  426. *pdu += sca_len;
  427. *length -= sca_len;
  428. /* TODO: Parse SCA Address */
  429. return sca_len + 2;
  430. }
  431. }
  432. return -EINVAL;
  433. }
  434. #/* TODO: implement */
  435. static int pdu_parse_timestamp(char ** pdu, size_t * length)
  436. {
  437. if(*length >= 14)
  438. {
  439. *pdu += 14;
  440. *length -= 14;
  441. return 14;
  442. }
  443. return -EINVAL;
  444. }
  445. #/* TODO: remove */
  446. static int check_encoding(const char* msg, unsigned length)
  447. {
  448. str_encoding_t possible_enc = get_encoding(RECODE_ENCODE, msg, length);
  449. if(possible_enc == STR_ENCODING_7BIT_HEX)
  450. return PDU_DCS_ALPABET_7BIT;
  451. return PDU_DCS_ALPABET_UCS2;
  452. }
  453. /*!
  454. * \brief Build PDU text for SMS
  455. * \param buffer -- pointer to place where PDU will be stored
  456. * \param length -- length of buffer
  457. * \param csca -- number of SMS center may be with leading '+' in International format
  458. * \param dst -- destination number for SMS may be with leading '+' in International format
  459. * \param msg -- SMS message in utf-8
  460. * \param valid_minutes -- Validity period
  461. * \param srr -- Status Report Request
  462. * \param sca_len -- pointer where length of SCA header (in bytes) will be stored
  463. * \return number of bytes written to buffer w/o trailing 0x1A or 0, -ENOMEM if buffer too short, -EINVAL on iconv recode errors, -E2BIG if message too long
  464. */
  465. EXPORT_DEF int pdu_build(char* buffer, size_t length, const char* csca, const char* dst, const char* msg, unsigned valid_minutes, int srr, int* sca_len)
  466. {
  467. char tmp;
  468. int len = 0;
  469. int data_len;
  470. int csca_toa = NUMBER_TYPE_INTERNATIONAL;
  471. int dst_toa = NUMBER_TYPE_INTERNATIONAL;
  472. int pdutype= PDUTYPE_MTI_SMS_SUBMIT | PDUTYPE_RD_ACCEPT | PDUTYPE_VPF_RELATIVE | PDUTYPE_SRR_NOT_REQUESTED | PDUTYPE_UDHI_NO_HEADER | PDUTYPE_RP_IS_NOT_SET;
  473. int dcs;
  474. unsigned dst_len;
  475. unsigned csa_len;
  476. unsigned msg_len;
  477. /* detect msg encoding and use 7Bit or UCS-2, not use 8Bit */
  478. msg_len = strlen(msg);
  479. dcs = check_encoding(msg, msg_len);
  480. /* cannot exceed 140 octets for no compressed or cannot exceed 160 septets for compressed */
  481. if(((PDU_DCS_ALPABET(dcs) == PDU_DCS_ALPABET_UCS2) && msg_len > 70) || (PDU_DCS_ALPABET(dcs) == PDU_DCS_ALPABET_8BIT && msg_len > 140) || msg_len > 160)
  482. {
  483. return -E2BIG;
  484. }
  485. if(csca[0] == '+')
  486. csca++;
  487. if(dst[0] == '+')
  488. dst++;
  489. /* count length of strings */
  490. csa_len = strlen(csca);
  491. dst_len = strlen(dst);
  492. /* check buffer has enougth space */
  493. if(length < ((csa_len == 0 ? 2 : 4 + ROUND_UP2(csa_len)) + 8 + ROUND_UP2(dst_len) + 8 + msg_len * 4 + 4))
  494. return -ENOMEM;
  495. /* SCA Length */
  496. /* Type-of-address of the SMSC */
  497. /* Address of SMSC */
  498. if(csa_len)
  499. {
  500. len += snprintf(buffer + len, length - len, "%02X%02X", 1 + LENGTH2OCTETS(csa_len), csca_toa);
  501. len += pdu_store_number(buffer + len, csca, csa_len);
  502. *sca_len = len;
  503. }
  504. else
  505. {
  506. buffer[len++] = '0';
  507. buffer[len++] = '0';
  508. *sca_len = 2;
  509. }
  510. if(srr)
  511. pdutype |= PDUTYPE_SRR_REQUESTED;
  512. /* PDU-type */
  513. /* TP-Message-Reference. The "00" value here lets the phone set the message reference number itself */
  514. /* Address-Length */
  515. /* Type-of-address of the sender number */
  516. len += snprintf(buffer + len, length - len, "%02X%02X%02X%02X", pdutype, PDU_MESSAGE_REFERENCE, dst_len, dst_toa);
  517. /* Destination address */
  518. len += pdu_store_number(buffer + len, dst, dst_len);
  519. /* TODO: also check message limit in 178 octet of TPDU (w/o SCA) */
  520. /* forward TP-User-Data */
  521. data_len = str_recode(RECODE_ENCODE, dcs == PDU_DCS_ALPABET_UCS2 ? STR_ENCODING_UCS2_HEX : STR_ENCODING_7BIT_HEX, msg, msg_len, buffer + len + 8, length - len - 11);
  522. if(data_len < 0)
  523. {
  524. return -EINVAL;
  525. }
  526. /* calc UDL */
  527. if(dcs == PDU_DCS_ALPABET_UCS2)
  528. msg_len = data_len / 2;
  529. /* TP-PID. Protocol identifier */
  530. /* TP-DCS. Data coding scheme */
  531. /* TP-Validity-Period */
  532. /* TP-User-Data-Length */
  533. tmp = buffer[len + 8];
  534. len += snprintf(buffer + len, length - len, "%02X%02X%02X%02X", PDU_PID_SMS, dcs, pdu_relative_validity(valid_minutes), msg_len);
  535. buffer[len] = tmp;
  536. len += data_len;
  537. return len;
  538. }
  539. #/* */
  540. static str_encoding_t pdu_dcs_alpabet2encoding(int alpabet)
  541. {
  542. str_encoding_t rv = STR_ENCODING_UNKNOWN;
  543. alpabet >>= PDU_DCS_ALPABET_SHIFT;
  544. switch(alpabet)
  545. {
  546. case (PDU_DCS_ALPABET_7BIT >> PDU_DCS_ALPABET_SHIFT):
  547. rv = STR_ENCODING_7BIT_HEX;
  548. break;
  549. case (PDU_DCS_ALPABET_8BIT >> PDU_DCS_ALPABET_SHIFT):
  550. rv = STR_ENCODING_8BIT_HEX;
  551. break;
  552. case (PDU_DCS_ALPABET_UCS2 >> PDU_DCS_ALPABET_SHIFT):
  553. rv = STR_ENCODING_UCS2_HEX;
  554. break;
  555. }
  556. return rv;
  557. }
  558. /*!
  559. * \brief Parse PDU
  560. * \param pdu -- SCA + TPDU
  561. * \param tpdu_length -- length of TPDU in octets
  562. * \return 0 on success
  563. */
  564. /* TODO: split long function */
  565. EXPORT_DEF const char * pdu_parse(char ** pdu, size_t tpdu_length, char * oa, size_t oa_len, str_encoding_t * oa_enc, char ** msg, str_encoding_t * msg_enc)
  566. {
  567. const char * err = NULL;
  568. size_t pdu_length = strlen(*pdu);
  569. /* decode SCA */
  570. int field_len = pdu_parse_sca(pdu, &pdu_length);
  571. if(field_len > 0)
  572. {
  573. if(tpdu_length * 2 == pdu_length)
  574. {
  575. int pdu_type = pdu_parse_byte(pdu, &pdu_length);
  576. if(pdu_type >= 0)
  577. {
  578. /* TODO: also handle PDUTYPE_MTI_SMS_SUBMIT_REPORT and PDUTYPE_MTI_SMS_STATUS_REPORT */
  579. if(PDUTYPE_MTI(pdu_type) == PDUTYPE_MTI_SMS_DELIVER)
  580. {
  581. int oa_digits = pdu_parse_byte(pdu, &pdu_length);
  582. if(oa_digits > 0)
  583. {
  584. int oa_toa;
  585. field_len = pdu_parse_number(pdu, &pdu_length, oa_digits, &oa_toa, oa, oa_len);
  586. if(field_len > 0)
  587. {
  588. int pid = pdu_parse_byte(pdu, &pdu_length);
  589. *oa_enc = STR_ENCODING_7BIT;
  590. if(pid >= 0)
  591. {
  592. /* TODO: support other types of messages */
  593. if(pid == PDU_PID_SMS)
  594. {
  595. int dcs = pdu_parse_byte(pdu, &pdu_length);
  596. if(dcs >= 0)
  597. {
  598. // TODO: support compression
  599. if( PDU_DCS_76(dcs) == PDU_DCS_76_00
  600. &&
  601. PDU_DCS_COMPRESSION(dcs) == PDU_DCS_NOT_COMPESSED
  602. &&
  603. (
  604. PDU_DCS_ALPABET(dcs) == PDU_DCS_ALPABET_7BIT
  605. ||
  606. PDU_DCS_ALPABET(dcs) == PDU_DCS_ALPABET_8BIT
  607. ||
  608. PDU_DCS_ALPABET(dcs) == PDU_DCS_ALPABET_UCS2
  609. )
  610. )
  611. {
  612. int ts = pdu_parse_timestamp(pdu, &pdu_length);
  613. *msg_enc = pdu_dcs_alpabet2encoding(PDU_DCS_ALPABET(dcs));
  614. if(ts >= 0)
  615. {
  616. int udl = pdu_parse_byte(pdu, &pdu_length);
  617. if(udl >= 0)
  618. {
  619. /* calculate number of octets in UD */
  620. if(PDU_DCS_ALPABET(dcs) == PDU_DCS_ALPABET_7BIT)
  621. udl = ((udl + 1) * 7) >> 3;
  622. if((size_t)udl * 2 == pdu_length)
  623. {
  624. if(PDUTYPE_UDHI(pdu_type) == PDUTYPE_UDHI_HAS_HEADER)
  625. {
  626. /* TODO: implement header parse */
  627. int udhl = pdu_parse_byte(pdu, &pdu_length);
  628. if(udhl >= 0)
  629. {
  630. /* NOTE: UDHL count octets no need calculation */
  631. if(pdu_length >= (size_t)(udhl * 2))
  632. {
  633. /* skip UDH */
  634. *pdu += udhl * 2;
  635. pdu_length -= udhl * 2;
  636. }
  637. else
  638. {
  639. err = "Invalid UDH";
  640. }
  641. }
  642. else
  643. {
  644. err = "Can't parse UDHL";
  645. }
  646. }
  647. /* save message */
  648. *msg = *pdu;
  649. }
  650. else
  651. {
  652. *pdu -= 2;
  653. err = "UDL not match with UD length";
  654. }
  655. }
  656. else
  657. {
  658. err = "Can't parse UDL";
  659. }
  660. }
  661. else
  662. {
  663. err = "Can't parse Timestamp";
  664. }
  665. }
  666. else
  667. {
  668. *pdu -= 2;
  669. err = "Unsupported DCS value";
  670. }
  671. }
  672. else
  673. {
  674. err = "Can't parse DSC";
  675. }
  676. }
  677. else
  678. {
  679. err = "Unhandled PID value, only SMS supported";
  680. }
  681. }
  682. else
  683. {
  684. err = "Can't parse PID";
  685. }
  686. }
  687. else
  688. {
  689. err = "Can't parse OA";
  690. }
  691. }
  692. else
  693. {
  694. err = "Can't parse length of OA";
  695. }
  696. }
  697. else
  698. {
  699. *pdu -= 2;
  700. err = "Unhandled PDU Type MTI only SMS-DELIVER supported";
  701. }
  702. }
  703. else
  704. {
  705. err = "Can't parse PDU Type";
  706. }
  707. }
  708. else
  709. {
  710. err = "TPDU length not matched with actual length";
  711. }
  712. }
  713. else
  714. {
  715. err = "Can't parse SCA";
  716. }
  717. return err;
  718. }