en50221_app_lowspeed.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. /*
  2. en50221 encoder An implementation for libdvb
  3. an implementation for the en50221 transport layer
  4. Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com>
  5. Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
  6. Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
  7. This library is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU Lesser General Public License as
  9. published by the Free Software Foundation; either version 2.1 of
  10. the License, or (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU Lesser General Public License for more details.
  15. You should have received a copy of the GNU Lesser General Public
  16. License along with this library; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. */
  19. #include <string.h>
  20. #include <libdvbmisc/dvbmisc.h>
  21. #include <pthread.h>
  22. #include "en50221_app_lowspeed.h"
  23. #include "en50221_app_tags.h"
  24. #include "asn_1.h"
  25. struct en50221_app_lowspeed_session {
  26. uint16_t session_number;
  27. uint8_t *block_chain;
  28. uint32_t block_length;
  29. struct en50221_app_lowspeed_session *next;
  30. };
  31. struct en50221_app_lowspeed {
  32. struct en50221_app_send_functions *funcs;
  33. en50221_app_lowspeed_command_callback command_callback;
  34. void *command_callback_arg;
  35. en50221_app_lowspeed_send_callback send_callback;
  36. void *send_callback_arg;
  37. struct en50221_app_lowspeed_session *sessions;
  38. pthread_mutex_t lock;
  39. };
  40. static int en50221_app_lowspeed_parse_connect_on_channel(struct en50221_app_lowspeed_command *command,
  41. uint8_t *data,
  42. int data_length);
  43. static int en50221_app_lowspeed_parse_command(struct en50221_app_lowspeed *lowspeed,
  44. uint8_t slot_id,
  45. uint16_t session_number,
  46. uint8_t *data,
  47. uint32_t data_length);
  48. static int en50221_app_lowspeed_parse_send(struct en50221_app_lowspeed *lowspeed,
  49. uint8_t slot_id,
  50. uint16_t session_number,
  51. int more_last,
  52. uint8_t *data,
  53. uint32_t data_length);
  54. struct en50221_app_lowspeed *en50221_app_lowspeed_create(struct en50221_app_send_functions *funcs)
  55. {
  56. struct en50221_app_lowspeed *lowspeed = NULL;
  57. // create structure and set it up
  58. lowspeed = malloc(sizeof(struct en50221_app_lowspeed));
  59. if (lowspeed == NULL) {
  60. return NULL;
  61. }
  62. lowspeed->funcs = funcs;
  63. lowspeed->command_callback = NULL;
  64. lowspeed->send_callback = NULL;
  65. lowspeed->sessions = NULL;
  66. pthread_mutex_init(&lowspeed->lock, NULL);
  67. // done
  68. return lowspeed;
  69. }
  70. void en50221_app_lowspeed_destroy(struct en50221_app_lowspeed *lowspeed)
  71. {
  72. struct en50221_app_lowspeed_session *cur_s = lowspeed->sessions;
  73. while (cur_s) {
  74. struct en50221_app_lowspeed_session *next = cur_s->next;
  75. if (cur_s->block_chain)
  76. free(cur_s->block_chain);
  77. free(cur_s);
  78. cur_s = next;
  79. }
  80. pthread_mutex_destroy(&lowspeed->lock);
  81. free(lowspeed);
  82. }
  83. void en50221_app_lowspeed_clear_session(struct en50221_app_lowspeed *lowspeed,
  84. uint16_t session_number)
  85. {
  86. pthread_mutex_lock(&lowspeed->lock);
  87. struct en50221_app_lowspeed_session *cur_s = lowspeed->sessions;
  88. struct en50221_app_lowspeed_session *prev_s = NULL;
  89. while (cur_s) {
  90. if (cur_s->session_number == session_number) {
  91. if (cur_s->block_chain)
  92. free(cur_s->block_chain);
  93. if (prev_s) {
  94. prev_s->next = cur_s->next;
  95. } else {
  96. lowspeed->sessions = cur_s->next;
  97. }
  98. free(cur_s);
  99. return;
  100. }
  101. prev_s = cur_s;
  102. cur_s = cur_s->next;
  103. }
  104. pthread_mutex_unlock(&lowspeed->lock);
  105. }
  106. void en50221_app_lowspeed_register_command_callback(struct en50221_app_lowspeed *lowspeed,
  107. en50221_app_lowspeed_command_callback callback,
  108. void *arg)
  109. {
  110. pthread_mutex_lock(&lowspeed->lock);
  111. lowspeed->command_callback = callback;
  112. lowspeed->command_callback_arg = arg;
  113. pthread_mutex_unlock(&lowspeed->lock);
  114. }
  115. void en50221_app_lowspeed_register_send_callback(struct en50221_app_lowspeed *lowspeed,
  116. en50221_app_lowspeed_send_callback callback,
  117. void *arg)
  118. {
  119. pthread_mutex_lock(&lowspeed->lock);
  120. lowspeed->send_callback = callback;
  121. lowspeed->send_callback_arg = arg;
  122. pthread_mutex_unlock(&lowspeed->lock);
  123. }
  124. int en50221_app_lowspeed_send_comms_reply(struct en50221_app_lowspeed *lowspeed,
  125. uint16_t session_number,
  126. uint8_t comms_reply_id,
  127. uint8_t return_value)
  128. {
  129. uint8_t data[6];
  130. data[0] = (TAG_COMMS_REPLY >> 16) & 0xFF;
  131. data[1] = (TAG_COMMS_REPLY >> 8) & 0xFF;
  132. data[2] = TAG_COMMS_REPLY & 0xFF;
  133. data[3] = 2;
  134. data[4] = comms_reply_id;
  135. data[5] = return_value;
  136. return lowspeed->funcs->send_data(lowspeed->funcs->arg,
  137. session_number, data, 6);
  138. }
  139. int en50221_app_lowspeed_send_comms_data(struct en50221_app_lowspeed *lowspeed,
  140. uint16_t session_number,
  141. uint8_t phase_id,
  142. uint32_t tx_data_length,
  143. uint8_t * tx_data)
  144. {
  145. uint8_t buf[10];
  146. // the spec defines this limit
  147. if (tx_data_length > 254) {
  148. return -1;
  149. }
  150. // set up the tag
  151. buf[0] = (TAG_COMMS_RECV_LAST >> 16) & 0xFF;
  152. buf[1] = (TAG_COMMS_RECV_LAST >> 8) & 0xFF;
  153. buf[2] = TAG_COMMS_RECV_LAST & 0xFF;
  154. // encode the length field
  155. int length_field_len;
  156. if ((length_field_len = asn_1_encode(tx_data_length + 1, buf + 3, 3)) < 0) {
  157. return -1;
  158. }
  159. // the phase_id
  160. buf[3 + length_field_len] = phase_id;
  161. // build the iovecs
  162. struct iovec iov[2];
  163. iov[0].iov_base = buf;
  164. iov[0].iov_len = 3 + length_field_len + 1;
  165. iov[1].iov_base = tx_data;
  166. iov[1].iov_len = tx_data_length;
  167. // create the data and send it
  168. return lowspeed->funcs->send_datav(lowspeed->funcs->arg,
  169. session_number, iov, 2);
  170. }
  171. int en50221_app_lowspeed_message(struct en50221_app_lowspeed *lowspeed,
  172. uint8_t slot_id,
  173. uint16_t session_number,
  174. uint32_t resource_id,
  175. uint8_t * data, uint32_t data_length)
  176. {
  177. (void) resource_id;
  178. // get the tag
  179. if (data_length < 3) {
  180. print(LOG_LEVEL, ERROR, 1, "Received short data\n");
  181. return -1;
  182. }
  183. uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
  184. switch (tag) {
  185. case TAG_COMMS_COMMAND:
  186. return en50221_app_lowspeed_parse_command(lowspeed,
  187. slot_id,
  188. session_number,
  189. data + 3,
  190. data_length - 3);
  191. case TAG_COMMS_SEND_LAST:
  192. return en50221_app_lowspeed_parse_send(lowspeed, slot_id,
  193. session_number, 1,
  194. data + 3,
  195. data_length - 3);
  196. case TAG_COMMS_SEND_MORE:
  197. return en50221_app_lowspeed_parse_send(lowspeed, slot_id,
  198. session_number, 0,
  199. data + 3,
  200. data_length - 3);
  201. }
  202. print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
  203. return -1;
  204. }
  205. static int en50221_app_lowspeed_parse_connect_on_channel(struct en50221_app_lowspeed_command *command,
  206. uint8_t *data,
  207. int data_length)
  208. {
  209. if (data_length < 3) {
  210. print(LOG_LEVEL, ERROR, 1, "Received short data\n");
  211. return -1;
  212. }
  213. // check the tag
  214. uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
  215. if (tag != TAG_CONNECTION_DESCRIPTOR) {
  216. print(LOG_LEVEL, ERROR, 1,
  217. "Received bad CONNECT_ON_CHANNEL\n");
  218. return -1;
  219. }
  220. data += 3;
  221. data_length -= 3;
  222. // parse the descriptor-length-field
  223. uint16_t asn_data_length;
  224. int length_field_len;
  225. if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
  226. print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
  227. return -1;
  228. }
  229. data += length_field_len;
  230. data_length -= length_field_len;
  231. // check length field
  232. if (asn_data_length > data_length) {
  233. print(LOG_LEVEL, ERROR, 1, "Received short data\n");
  234. return -1;
  235. }
  236. if (asn_data_length < 1) {
  237. print(LOG_LEVEL, ERROR, 1, "Received short data\n");
  238. return -1;
  239. }
  240. // get the descriptor type
  241. command->u.connect_on_channel.descriptor_type = data[0];
  242. data++;
  243. data_length--;
  244. asn_data_length--;
  245. // deal with the descriptor itself
  246. switch (command->u.connect_on_channel.descriptor_type) {
  247. case CONNECTION_DESCRIPTOR_TYPE_TELEPHONE:
  248. {
  249. // get the raw descriptor and validate length
  250. struct descriptor *d = (struct descriptor *) data;
  251. if (asn_data_length < 2) {
  252. print(LOG_LEVEL, ERROR, 1,
  253. "Received short data\n");
  254. return -1;
  255. }
  256. if (asn_data_length != (2 + d->len)) {
  257. print(LOG_LEVEL, ERROR, 1,
  258. "Received short data\n");
  259. return -1;
  260. }
  261. if (d->tag != dtag_dvb_telephone) {
  262. print(LOG_LEVEL, ERROR, 1,
  263. "Received invalid telephone descriptor\n");
  264. return -1;
  265. }
  266. // parse the telephone descriptor
  267. command->u.connect_on_channel.descriptor.telephone = dvb_telephone_descriptor_codec(d);
  268. if (command->u.connect_on_channel.descriptor.telephone == NULL) {
  269. print(LOG_LEVEL, ERROR, 1,
  270. "Received invalid telephone descriptor\n");
  271. return -1;
  272. }
  273. data += 2 + d->len;
  274. data_length -= 2 + d->len;
  275. break;
  276. }
  277. case CONNECTION_DESCRIPTOR_TYPE_CABLE:
  278. if (asn_data_length != 1) {
  279. print(LOG_LEVEL, ERROR, 1,
  280. "Received short data\n");
  281. return -1;
  282. }
  283. command->u.connect_on_channel.descriptor.cable_channel_id = data[0];
  284. data++;
  285. data_length--;
  286. break;
  287. default:
  288. print(LOG_LEVEL, ERROR, 1,
  289. "Received unknown connection descriptor %02x\n",
  290. command->u.connect_on_channel.descriptor_type);
  291. return -1;
  292. }
  293. // parse the last bit
  294. if (data_length != 2) {
  295. print(LOG_LEVEL, ERROR, 1, "Received short data\n");
  296. return -1;
  297. }
  298. command->u.connect_on_channel.retry_count = data[0];
  299. command->u.connect_on_channel.timeout = data[1];
  300. // ok
  301. return 0;
  302. }
  303. static int en50221_app_lowspeed_parse_command(struct en50221_app_lowspeed *lowspeed,
  304. uint8_t slot_id,
  305. uint16_t session_number,
  306. uint8_t * data,
  307. uint32_t data_length)
  308. {
  309. // first of all, decode the length field
  310. uint16_t asn_data_length;
  311. int length_field_len;
  312. if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
  313. print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
  314. return -1;
  315. }
  316. // check it
  317. if (asn_data_length < 1) {
  318. print(LOG_LEVEL, ERROR, 1, "Received short data\n");
  319. return -1;
  320. }
  321. if (asn_data_length > (data_length - length_field_len)) {
  322. print(LOG_LEVEL, ERROR, 1, "Received short data\n");
  323. return -1;
  324. }
  325. data += length_field_len;
  326. // get command id
  327. uint8_t command_id = data[0];
  328. data++;
  329. asn_data_length--;
  330. // parse the command
  331. struct en50221_app_lowspeed_command command;
  332. switch (command_id) {
  333. case COMMS_COMMAND_ID_CONNECT_ON_CHANNEL:
  334. if (en50221_app_lowspeed_parse_connect_on_channel
  335. (&command, data, asn_data_length)) {
  336. return -1;
  337. }
  338. break;
  339. case COMMS_COMMAND_ID_SET_PARAMS:
  340. if (asn_data_length != 2) {
  341. print(LOG_LEVEL, ERROR, 1,
  342. "Received short data\n");
  343. return -1;
  344. }
  345. command.u.set_params.buffer_size = data[0];
  346. command.u.set_params.timeout = data[1];
  347. break;
  348. case COMMS_COMMAND_ID_GET_NEXT_BUFFER:
  349. if (asn_data_length != 1) {
  350. print(LOG_LEVEL, ERROR, 1,
  351. "Received short data\n");
  352. return -1;
  353. }
  354. command.u.get_next_buffer.phase_id = data[0];
  355. break;
  356. case COMMS_COMMAND_ID_DISCONNECT_ON_CHANNEL:
  357. case COMMS_COMMAND_ID_ENQUIRE_STATUS:
  358. break;
  359. default:
  360. print(LOG_LEVEL, ERROR, 1,
  361. "Received unexpected command_id %02x\n", command_id);
  362. return -1;
  363. }
  364. // tell the app
  365. pthread_mutex_lock(&lowspeed->lock);
  366. en50221_app_lowspeed_command_callback cb = lowspeed->command_callback;
  367. void *cb_arg = lowspeed->command_callback_arg;
  368. pthread_mutex_unlock(&lowspeed->lock);
  369. if (cb) {
  370. return cb(cb_arg, slot_id, session_number, command_id,
  371. &command);
  372. }
  373. return 0;
  374. }
  375. static int en50221_app_lowspeed_parse_send(struct en50221_app_lowspeed *lowspeed,
  376. uint8_t slot_id,
  377. uint16_t session_number,
  378. int more_last,
  379. uint8_t *data,
  380. uint32_t data_length)
  381. {
  382. // first of all, decode the length field
  383. uint16_t asn_data_length;
  384. int length_field_len;
  385. if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
  386. print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
  387. return -1;
  388. }
  389. // check it
  390. if (asn_data_length > (data_length - length_field_len)) {
  391. print(LOG_LEVEL, ERROR, 1, "Received short data\n");
  392. return -1;
  393. }
  394. // skip over the length field
  395. data += length_field_len;
  396. // find previous session
  397. pthread_mutex_lock(&lowspeed->lock);
  398. struct en50221_app_lowspeed_session *cur_s = lowspeed->sessions;
  399. while (cur_s) {
  400. if (cur_s->session_number == session_number)
  401. break;
  402. cur_s = cur_s->next;
  403. }
  404. // more data is still to come
  405. if (!more_last) {
  406. // if there was no previous session, create one
  407. if (cur_s == NULL) {
  408. cur_s = malloc(sizeof(struct en50221_app_lowspeed_session));
  409. if (cur_s == NULL) {
  410. print(LOG_LEVEL, ERROR, 1,
  411. "Ran out of memory\n");
  412. pthread_mutex_unlock(&lowspeed->lock);
  413. return -1;
  414. }
  415. cur_s->session_number = session_number;
  416. cur_s->block_chain = NULL;
  417. cur_s->block_length = 0;
  418. cur_s->next = lowspeed->sessions;
  419. lowspeed->sessions = cur_s;
  420. }
  421. // append the data
  422. uint8_t *new_data = realloc(cur_s->block_chain,
  423. cur_s->block_length + asn_data_length);
  424. if (new_data == NULL) {
  425. print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n");
  426. pthread_mutex_unlock(&lowspeed->lock);
  427. return -1;
  428. }
  429. memcpy(new_data + cur_s->block_length, data, asn_data_length);
  430. cur_s->block_chain = new_data;
  431. cur_s->block_length += asn_data_length;
  432. // done
  433. pthread_mutex_unlock(&lowspeed->lock);
  434. return 0;
  435. }
  436. // we hit the last of a possible chain of fragments
  437. int do_free = 0;
  438. if (cur_s != NULL) {
  439. // we have a preceding fragment - need to append
  440. uint8_t *new_data = realloc(cur_s->block_chain,
  441. cur_s->block_length + asn_data_length);
  442. if (new_data == NULL) {
  443. print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n");
  444. pthread_mutex_unlock(&lowspeed->lock);
  445. return -1;
  446. }
  447. memcpy(new_data + cur_s->block_length, data, asn_data_length);
  448. asn_data_length = cur_s->block_length + asn_data_length;
  449. data = new_data;
  450. cur_s->block_chain = NULL;
  451. cur_s->block_length = 0;
  452. do_free = 1;
  453. }
  454. // check the reassembled data length
  455. if (asn_data_length < 1) {
  456. pthread_mutex_unlock(&lowspeed->lock);
  457. print(LOG_LEVEL, ERROR, 1, "Received short data\n");
  458. if (do_free)
  459. free(data);
  460. return -1;
  461. }
  462. // now, parse the data
  463. uint8_t phase_id = data[0];
  464. // tell the app
  465. en50221_app_lowspeed_send_callback cb = lowspeed->send_callback;
  466. void *cb_arg = lowspeed->send_callback_arg;
  467. pthread_mutex_unlock(&lowspeed->lock);
  468. int cbstatus = 0;
  469. if (cb) {
  470. cbstatus =
  471. cb(cb_arg, slot_id, session_number, phase_id, data + 1, asn_data_length - 1);
  472. }
  473. // done
  474. if (do_free)
  475. free(data);
  476. return cbstatus;
  477. }