1 /*
2 en50221 encoder An implementation for libdvb
3 an implementation for the en50221 transport layer
4
5 Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com>
6 Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
7 Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
8
9 This library is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as
11 published by the Free Software Foundation; either version 2.1 of
12 the License, or (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <fcntl.h>
28 #include <sys/ioctl.h>
29 #include <time.h>
30 #include <libdvbmisc/dvbmisc.h>
31 #include <sys/uio.h>
32 #include <pthread.h>
33 #include "en50221_transport.h"
34 #include "en50221_session.h"
35 #include "en50221_errno.h"
36 #include "asn_1.h"
37
38
39 // these are the possible session statuses
40 #define S_STATUS_OPEN 0x00 // session is opened
41 #define S_STATUS_CLOSE_NO_RES 0xF0 // could not open session, no proper resource available
42 #define S_STATUS_CLOSE_RES_UNAVAILABLE 0xF1 // could not open session, resource unavailable
43 #define S_STATUS_CLOSE_RES_LOW_VERSION 0xF2 // could not open session, resource version too low
44 #define S_STATUS_CLOSE_RES_BUSY 0xF3 // could not open session, resource is busy
45
46 #define ST_OPEN_SESSION_REQ 0x91 // h<--m
47 #define ST_OPEN_SESSION_RES 0x92 // h-->m
48 #define ST_CREATE_SESSION 0x93 // h-->m
49 #define ST_CREATE_SESSION_RES 0x94 // h<--m
50 #define ST_CLOSE_SESSION_REQ 0x95 // h<->m
51 #define ST_CLOSE_SESSION_RES 0x96 // h<->m
52 #define ST_SESSION_NUMBER 0x90 // h<->m
53
54 #define S_STATE_IDLE 0x01 // this session is not in use
55 #define S_STATE_ACTIVE 0x02 // this session is in use
56 #define S_STATE_IN_CREATION 0x04 // this session waits for a ST_CREATE_SESSION_RES to become active
57 #define S_STATE_IN_DELETION 0x08 // this session waits for ST_CLOSE_SESSION_RES to become idle again
58
59
60 // for each session we store its identifier, the resource-id
61 // it is linked to and the callback of the specific resource
62 struct en50221_session {
63 uint8_t state;
64 uint32_t resource_id;
65 uint8_t slot_id;
66 uint8_t connection_id;
67
68 en50221_sl_resource_callback callback;
69 void *callback_arg;
70
71 pthread_mutex_t session_lock;
72 };
73
74 struct en50221_session_layer {
75 uint32_t max_sessions;
76 struct en50221_transport_layer *tl;
77
78 en50221_sl_lookup_callback lookup;
79 void *lookup_arg;
80
81 en50221_sl_session_callback session;
82 void *session_arg;
83
84 pthread_mutex_t global_lock;
85 pthread_mutex_t setcallback_lock;
86
87 int error;
88
89 struct en50221_session *sessions;
90 };
91
92 static void en50221_sl_transport_callback(void *arg, int reason,
93 uint8_t * data,
94 uint32_t data_length,
95 uint8_t slot_id,
96 uint8_t connection_id);
97 static int en50221_sl_alloc_new_session(struct en50221_session_layer *sl,
98 uint32_t resource_id,
99 uint8_t slot_id,
100 uint8_t connection_id,
101 en50221_sl_resource_callback
102 callback, void *arg);
103
104
105
106
en50221_sl_create(struct en50221_transport_layer * tl,uint32_t max_sessions)107 struct en50221_session_layer *en50221_sl_create(struct en50221_transport_layer *tl,
108 uint32_t max_sessions)
109 {
110 struct en50221_session_layer *sl = NULL;
111 uint32_t i;
112
113 // setup structure
114 sl = (struct en50221_session_layer *)
115 malloc(sizeof(struct en50221_session_layer));
116 if (sl == NULL)
117 goto error_exit;
118 sl->max_sessions = max_sessions;
119 sl->lookup = NULL;
120 sl->session = NULL;
121 sl->tl = tl;
122 sl->error = 0;
123
124 // init the mutex
125 pthread_mutex_init(&sl->global_lock, NULL);
126 pthread_mutex_init(&sl->setcallback_lock, NULL);
127
128 // create the slots
129 sl->sessions = malloc(sizeof(struct en50221_session) * max_sessions);
130 if (sl->sessions == NULL)
131 goto error_exit;
132
133 // set them up
134 for (i = 0; i < max_sessions; i++) {
135 sl->sessions[i].state = S_STATE_IDLE;
136 sl->sessions[i].callback = NULL;
137
138 pthread_mutex_init(&sl->sessions[i].session_lock, NULL);
139 }
140
141 // register ourselves with the transport layer
142 en50221_tl_register_callback(tl, en50221_sl_transport_callback, sl);
143
144 return sl;
145
146 error_exit:
147 en50221_sl_destroy(sl);
148 return NULL;
149 }
150
en50221_sl_destroy(struct en50221_session_layer * sl)151 void en50221_sl_destroy(struct en50221_session_layer *sl)
152 {
153 uint32_t i;
154
155 if (sl) {
156 if (sl->sessions) {
157 for (i = 0; i < sl->max_sessions; i++) {
158 pthread_mutex_destroy(&sl->sessions[i].session_lock);
159 }
160 free(sl->sessions);
161 }
162
163 pthread_mutex_destroy(&sl->setcallback_lock);
164 pthread_mutex_destroy(&sl->global_lock);
165
166 free(sl);
167 }
168 }
169
en50221_sl_get_error(struct en50221_session_layer * sl)170 int en50221_sl_get_error(struct en50221_session_layer *sl)
171 {
172 return sl->error;
173 }
174
en50221_sl_register_lookup_callback(struct en50221_session_layer * sl,en50221_sl_lookup_callback callback,void * arg)175 void en50221_sl_register_lookup_callback(struct en50221_session_layer *sl,
176 en50221_sl_lookup_callback
177 callback, void *arg)
178 {
179 pthread_mutex_lock(&sl->setcallback_lock);
180 sl->lookup = callback;
181 sl->lookup_arg = arg;
182 pthread_mutex_unlock(&sl->setcallback_lock);
183 }
184
en50221_sl_register_session_callback(struct en50221_session_layer * sl,en50221_sl_session_callback callback,void * arg)185 void en50221_sl_register_session_callback(struct en50221_session_layer *sl,
186 en50221_sl_session_callback
187 callback, void *arg)
188 {
189 pthread_mutex_lock(&sl->setcallback_lock);
190 sl->session = callback;
191 sl->session_arg = arg;
192 pthread_mutex_unlock(&sl->setcallback_lock);
193 }
194
en50221_sl_create_session(struct en50221_session_layer * sl,int slot_id,uint8_t connection_id,uint32_t resource_id,en50221_sl_resource_callback callback,void * arg)195 int en50221_sl_create_session(struct en50221_session_layer *sl,
196 int slot_id, uint8_t connection_id,
197 uint32_t resource_id,
198 en50221_sl_resource_callback callback,
199 void *arg)
200 {
201 // lookup next free session_id:
202 pthread_mutex_lock(&sl->global_lock);
203 int session_number =
204 en50221_sl_alloc_new_session(sl, resource_id, slot_id,
205 connection_id, callback, arg);
206 if (session_number == -1) {
207 pthread_mutex_unlock(&sl->global_lock);
208 return -1;
209 }
210 pthread_mutex_unlock(&sl->global_lock);
211
212 // make up the header
213 uint8_t hdr[8];
214 hdr[0] = ST_CREATE_SESSION;
215 hdr[1] = 6;
216 hdr[2] = resource_id >> 24;
217 hdr[3] = resource_id >> 16;
218 hdr[4] = resource_id >> 8;
219 hdr[5] = resource_id;
220 hdr[6] = session_number >> 8;
221 hdr[7] = session_number;
222
223 // send this command
224 if (en50221_tl_send_data(sl->tl, slot_id, connection_id, hdr, 8)) {
225 pthread_mutex_lock(&sl->sessions[session_number].session_lock);
226 if (sl->sessions[session_number].state == S_STATE_IN_CREATION) {
227 sl->sessions[session_number].state = S_STATE_IDLE;
228 }
229 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
230
231 sl->error = en50221_tl_get_error(sl->tl);
232 return -1;
233 }
234 // ok.
235 return session_number;
236 }
237
en50221_sl_destroy_session(struct en50221_session_layer * sl,uint16_t session_number)238 int en50221_sl_destroy_session(struct en50221_session_layer *sl,
239 uint16_t session_number)
240 {
241 if (session_number >= sl->max_sessions) {
242 sl->error = EN50221ERR_BADSESSIONNUMBER;
243 return -1;
244 }
245
246 pthread_mutex_lock(&sl->sessions[session_number].session_lock);
247 if (!(sl->sessions[session_number].state & (S_STATE_ACTIVE | S_STATE_IN_DELETION))) {
248 sl->error = EN50221ERR_BADSESSIONNUMBER;
249 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
250 return -1;
251 }
252 // set the state
253 sl->sessions[session_number].state = S_STATE_IN_DELETION;
254
255 // get essential details
256 uint8_t slot_id = sl->sessions[session_number].slot_id;
257 uint8_t connection_id = sl->sessions[session_number].connection_id;
258 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
259
260 // sendit
261 uint8_t hdr[4];
262 hdr[0] = ST_CLOSE_SESSION_REQ;
263 hdr[1] = 2;
264 hdr[2] = session_number >> 8;
265 hdr[3] = session_number;
266 if (en50221_tl_send_data(sl->tl, slot_id, connection_id, hdr, 4)) {
267 pthread_mutex_lock(&sl->sessions[session_number].session_lock);
268 if (sl->sessions[session_number].state == S_STATE_IN_DELETION) {
269 sl->sessions[session_number].state = S_STATE_IDLE;
270 }
271 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
272
273 sl->error = en50221_tl_get_error(sl->tl);
274 return -1;
275 }
276
277 return 0;
278 }
279
en50221_sl_send_data(struct en50221_session_layer * sl,uint16_t session_number,uint8_t * data,uint16_t data_length)280 int en50221_sl_send_data(struct en50221_session_layer *sl,
281 uint16_t session_number,
282 uint8_t *data,
283 uint16_t data_length)
284 {
285 if (session_number >= sl->max_sessions) {
286 sl->error = EN50221ERR_BADSESSIONNUMBER;
287 return -1;
288 }
289
290 pthread_mutex_lock(&sl->sessions[session_number].session_lock);
291 if (sl->sessions[session_number].state != S_STATE_ACTIVE) {
292 sl->error = EN50221ERR_BADSESSIONNUMBER;
293 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
294 return -1;
295 }
296 // get essential details
297 uint8_t slot_id = sl->sessions[session_number].slot_id;
298 uint8_t connection_id = sl->sessions[session_number].connection_id;
299 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
300
301 // sendit
302 struct iovec iov[2];
303 uint8_t hdr[4];
304 hdr[0] = ST_SESSION_NUMBER;
305 hdr[1] = 2;
306 hdr[2] = session_number >> 8;
307 hdr[3] = session_number;
308 iov[0].iov_base = hdr;
309 iov[0].iov_len = 4;
310 iov[1].iov_base = data;
311 iov[1].iov_len = data_length;
312 if (en50221_tl_send_datav(sl->tl, slot_id, connection_id, iov, 2)) {
313 sl->error = en50221_tl_get_error(sl->tl);
314 return -1;
315 }
316
317 return 0;
318 }
319
en50221_sl_send_datav(struct en50221_session_layer * sl,uint16_t session_number,struct iovec * vector,int iov_count)320 int en50221_sl_send_datav(struct en50221_session_layer *sl,
321 uint16_t session_number,
322 struct iovec *vector,
323 int iov_count)
324 {
325 if (session_number >= sl->max_sessions) {
326 sl->error = EN50221ERR_BADSESSIONNUMBER;
327 return -1;
328 }
329
330 pthread_mutex_lock(&sl->sessions[session_number].session_lock);
331 if (sl->sessions[session_number].state != S_STATE_ACTIVE) {
332 sl->error = EN50221ERR_BADSESSIONNUMBER;
333 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
334 return -1;
335 }
336 if (iov_count > 9) {
337 sl->error = EN50221ERR_IOVLIMIT;
338 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
339 return -1;
340 }
341 uint8_t slot_id = sl->sessions[session_number].slot_id;
342 uint8_t connection_id = sl->sessions[session_number].connection_id;
343 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
344
345 // make up the header
346 struct iovec out_iov[10];
347 uint8_t hdr[4];
348 hdr[0] = ST_SESSION_NUMBER;
349 hdr[1] = 2;
350 hdr[2] = session_number >> 8;
351 hdr[3] = session_number;
352 out_iov[0].iov_base = hdr;
353 out_iov[0].iov_len = 4;
354
355 // make up the data
356 memcpy(&out_iov[1], vector, iov_count * sizeof(struct iovec));
357
358 // send this command
359 if (en50221_tl_send_datav(sl->tl, slot_id, connection_id, out_iov, iov_count + 1)) {
360 sl->error = en50221_tl_get_error(sl->tl);
361 return -1;
362 }
363 return 0;
364 }
365
en50221_sl_broadcast_data(struct en50221_session_layer * sl,int slot_id,uint32_t resource_id,uint8_t * data,uint16_t data_length)366 int en50221_sl_broadcast_data(struct en50221_session_layer *sl,
367 int slot_id, uint32_t resource_id,
368 uint8_t *data, uint16_t data_length)
369 {
370 uint32_t i;
371
372 for (i = 0; i < sl->max_sessions; i++) {
373 pthread_mutex_lock(&sl->sessions[i].session_lock);
374
375 if (sl->sessions[i].state != S_STATE_ACTIVE) {
376 pthread_mutex_unlock(&sl->sessions[i].session_lock);
377 continue;
378 }
379 if ((slot_id != -1)
380 && (slot_id != sl->sessions[i].slot_id)) {
381 pthread_mutex_unlock(&sl->sessions[i].session_lock);
382 continue;
383 }
384
385 if (sl->sessions[i].resource_id == resource_id) {
386 pthread_mutex_unlock(&sl->sessions[i].session_lock);
387 en50221_sl_send_data(sl, i, data, data_length);
388 } else {
389 pthread_mutex_unlock(&sl->sessions[i].session_lock);
390 }
391 }
392
393 return 0;
394 }
395
396
397
en50221_sl_handle_open_session_request(struct en50221_session_layer * sl,uint8_t * data,uint32_t data_length,uint8_t slot_id,uint8_t connection_id)398 static void en50221_sl_handle_open_session_request(struct en50221_session_layer *sl,
399 uint8_t *data,
400 uint32_t data_length,
401 uint8_t slot_id,
402 uint8_t connection_id)
403 {
404 // check
405 if (data_length < 5) {
406 print(LOG_LEVEL, ERROR, 1,
407 "Received data with invalid length from module on slot %02x\n",
408 slot_id);
409 return;
410 }
411 if (data[0] != 4) {
412 print(LOG_LEVEL, ERROR, 1,
413 "Received data with invalid length from module on slot %02x\n",
414 slot_id);
415 return;
416 }
417 // get the resource id
418 uint32_t requested_resource_id =
419 (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
420
421 // get lookup callback details
422 pthread_mutex_lock(&sl->setcallback_lock);
423 en50221_sl_lookup_callback lcb = sl->lookup;
424 void *lcb_arg = sl->lookup_arg;
425 pthread_mutex_unlock(&sl->setcallback_lock);
426
427 // first of all, lookup this resource id
428 int status = S_STATUS_CLOSE_NO_RES;
429 en50221_sl_resource_callback resource_callback = NULL;
430 void *resource_arg = NULL;
431 uint32_t connected_resource_id;
432 if (lcb) {
433 status =
434 lcb(lcb_arg, slot_id, requested_resource_id,
435 &resource_callback, &resource_arg,
436 &connected_resource_id);
437 switch (status) {
438 case 0:
439 status = S_STATUS_OPEN;
440 break;
441
442 case -1:
443 status = S_STATUS_CLOSE_NO_RES;
444 break;
445
446 case -2:
447 status = S_STATUS_CLOSE_RES_LOW_VERSION;
448 break;
449
450 case -3:
451 status = S_STATUS_CLOSE_RES_UNAVAILABLE;
452 break;
453 }
454 }
455 // if we found it, get a new session for it
456 int session_number = -1;
457 if (status == S_STATUS_OPEN) {
458 // lookup next free session_id:
459 pthread_mutex_lock(&sl->global_lock);
460 session_number =
461 en50221_sl_alloc_new_session(sl, connected_resource_id,
462 slot_id, connection_id,
463 resource_callback,
464 resource_arg);
465 pthread_mutex_unlock(&sl->global_lock);
466
467 if (session_number == -1) {
468 status = S_STATUS_CLOSE_NO_RES;
469 } else {
470 // inform upper layers/ check availability
471 pthread_mutex_lock(&sl->setcallback_lock);
472 en50221_sl_session_callback cb = sl->session;
473 void *cb_arg = sl->session_arg;
474 pthread_mutex_unlock(&sl->setcallback_lock);
475 if (cb) {
476 if (cb(cb_arg, S_SCALLBACK_REASON_CAMCONNECTING,
477 slot_id, session_number,
478 connected_resource_id)) {
479 status = S_STATUS_CLOSE_RES_BUSY;
480 }
481 } else {
482 status = S_STATUS_CLOSE_RES_UNAVAILABLE;
483 }
484 }
485 }
486 // send response
487 uint8_t hdr[9];
488 hdr[0] = ST_OPEN_SESSION_RES;
489 hdr[1] = 7;
490 hdr[2] = status;
491 hdr[3] = connected_resource_id >> 24;
492 hdr[4] = connected_resource_id >> 16;
493 hdr[5] = connected_resource_id >> 8;
494 hdr[6] = connected_resource_id;
495 hdr[7] = session_number >> 8;
496 hdr[8] = session_number;
497 if (en50221_tl_send_data(sl->tl, slot_id, connection_id, hdr, 9)) {
498 print(LOG_LEVEL, ERROR, 1,
499 "Transport layer error %i occurred\n",
500 en50221_tl_get_error(sl->tl));
501 status = S_STATUS_CLOSE_NO_RES;
502 // fallthrough
503 }
504 // inform upper layers what happened
505 if (session_number != -1) {
506 // setup session state apppropriately from upper layer response
507 pthread_mutex_lock(&sl->sessions[session_number].session_lock);
508 if (status != S_STATUS_OPEN) {
509 sl->sessions[session_number].state = S_STATE_IDLE;
510 } else {
511 sl->sessions[session_number].state = S_STATE_ACTIVE;
512 }
513 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
514
515 // tell upper layers
516 if (sl->sessions[session_number].state == S_STATE_ACTIVE) {
517 pthread_mutex_lock(&sl->setcallback_lock);
518 en50221_sl_session_callback cb = sl->session;
519 void *cb_arg = sl->session_arg;
520 pthread_mutex_unlock(&sl->setcallback_lock);
521
522 if (status == S_STATUS_OPEN) {
523 if (cb)
524 cb(cb_arg,
525 S_SCALLBACK_REASON_CAMCONNECTED,
526 slot_id, session_number,
527 connected_resource_id);
528 } else {
529 sl->sessions[session_number].state =
530 S_STATE_IDLE;
531 if (cb)
532 cb(cb_arg,
533 S_SCALLBACK_REASON_CAMCONNECTFAIL,
534 slot_id, session_number,
535 connected_resource_id);
536 }
537 }
538 }
539 }
540
en50221_sl_handle_close_session_request(struct en50221_session_layer * sl,uint8_t * data,uint32_t data_length,uint8_t slot_id,uint8_t connection_id)541 static void en50221_sl_handle_close_session_request(struct en50221_session_layer *sl,
542 uint8_t * data,
543 uint32_t data_length,
544 uint8_t slot_id,
545 uint8_t connection_id)
546 {
547 // check
548 if (data_length < 3) {
549 print(LOG_LEVEL, ERROR, 1,
550 "Received data with invalid length from module on slot %02x\n",
551 slot_id);
552 return;
553 }
554 if (data[0] != 2) {
555 print(LOG_LEVEL, ERROR, 1,
556 "Received data with invalid length from module on slot %02x\n",
557 slot_id);
558 return;
559 }
560 // extract session number
561 uint16_t session_number = (data[1] << 8) | data[2];
562
563 // check session number is ok
564 uint8_t code = 0x00;
565 uint32_t resource_id = 0;
566 if (session_number >= sl->max_sessions) {
567 code = 0xF0; // session close error
568 print(LOG_LEVEL, ERROR, 1, "Received bad session id %i\n",
569 slot_id);
570 } else {
571 pthread_mutex_lock(&sl->sessions[session_number].
572 session_lock);
573 if (slot_id != sl->sessions[session_number].slot_id) {
574 print(LOG_LEVEL, ERROR, 1,
575 "Received unexpected session on invalid slot %i\n",
576 slot_id);
577 code = 0xF0; // session close error
578 }
579 if (connection_id != sl->sessions[session_number].connection_id) {
580 print(LOG_LEVEL, ERROR, 1,
581 "Received unexpected session on invalid slot %i\n",
582 slot_id);
583 code = 0xF0; // session close error
584 }
585 if (!(sl->sessions[session_number].state & (S_STATE_ACTIVE | S_STATE_IN_DELETION))) {
586 print(LOG_LEVEL, ERROR, 1,
587 "Received unexpected session on invalid slot %i\n",
588 slot_id);
589 code = 0xF0; // session close error
590 }
591
592 if (code == 0x00) {
593 sl->sessions[session_number].state = S_STATE_IDLE;
594 code = 0x00; // close ok
595 }
596 resource_id = sl->sessions[session_number].resource_id;
597 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
598 }
599
600 // make up the response
601 uint8_t hdr[5];
602 hdr[0] = ST_CLOSE_SESSION_RES;
603 hdr[1] = 3;
604 hdr[2] = code;
605 hdr[3] = session_number >> 8;
606 hdr[4] = session_number;
607
608 // sendit
609 if (en50221_tl_send_data(sl->tl, slot_id, connection_id, hdr, 5)) {
610 print(LOG_LEVEL, ERROR, 1,
611 "Transport layer reports error %i on slot %i\n",
612 en50221_tl_get_error(sl->tl), slot_id);
613 }
614 // callback to announce destruction to resource if it was ok
615 if (code == 0x00) {
616 pthread_mutex_lock(&sl->setcallback_lock);
617 en50221_sl_session_callback cb = sl->session;
618 void *cb_arg = sl->session_arg;
619 pthread_mutex_unlock(&sl->setcallback_lock);
620
621 if (cb)
622 cb(cb_arg, S_SCALLBACK_REASON_CLOSE, slot_id,
623 session_number, resource_id);
624 }
625 }
626
en50221_sl_handle_create_session_response(struct en50221_session_layer * sl,uint8_t * data,uint32_t data_length,uint8_t slot_id,uint8_t connection_id)627 static void en50221_sl_handle_create_session_response(struct en50221_session_layer *sl,
628 uint8_t * data,
629 uint32_t data_length,
630 uint8_t slot_id,
631 uint8_t connection_id)
632 {
633 // check
634 if (data_length < 8) {
635 print(LOG_LEVEL, ERROR, 1,
636 "Received data with invalid length from module on slot %02x\n",
637 slot_id);
638 return;
639 }
640 if (data[0] != 7) {
641 print(LOG_LEVEL, ERROR, 1,
642 "Received data with invalid length from module on slot %02x\n",
643 slot_id);
644 return;
645 }
646 // extract session number
647 uint16_t session_number = (data[5] << 8) | data[6];
648
649 // check session number is ok
650 if (session_number >= sl->max_sessions) {
651 print(LOG_LEVEL, ERROR, 1, "Received bad session id %i\n",
652 slot_id);
653 return;
654 }
655
656 pthread_mutex_lock(&sl->sessions[session_number].session_lock);
657 if (slot_id != sl->sessions[session_number].slot_id) {
658 print(LOG_LEVEL, ERROR, 1,
659 "Received unexpected session on invalid slot %i\n",
660 slot_id);
661 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
662 return;
663 }
664 if (connection_id != sl->sessions[session_number].connection_id) {
665 print(LOG_LEVEL, ERROR, 1,
666 "Received unexpected session on invalid slot %i\n",
667 slot_id);
668 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
669 return;
670 }
671 if (sl->sessions[session_number].state != S_STATE_IN_CREATION) {
672 print(LOG_LEVEL, ERROR, 1,
673 "Received unexpected session on invalid slot %i\n",
674 slot_id);
675 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
676 return;
677 }
678 // extract status
679 if (data[1] != S_STATUS_OPEN) {
680 print(LOG_LEVEL, ERROR, 1,
681 "Session creation failed 0x%02x\n", data[1]);
682 sl->sessions[session_number].state = S_STATE_IDLE;
683 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
684
685 // inform upper layers
686 pthread_mutex_lock(&sl->setcallback_lock);
687 en50221_sl_session_callback cb = sl->session;
688 void *cb_arg = sl->session_arg;
689 pthread_mutex_unlock(&sl->setcallback_lock);
690 if (cb)
691 cb(cb_arg, S_SCALLBACK_REASON_CONNECTFAIL, slot_id,
692 session_number,
693 sl->sessions[session_number].resource_id);
694 return;
695 }
696 // set it active
697 sl->sessions[session_number].state = S_STATE_ACTIVE;
698 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
699
700 // inform upper layers
701 pthread_mutex_lock(&sl->setcallback_lock);
702 en50221_sl_session_callback cb = sl->session;
703 void *cb_arg = sl->session_arg;
704 pthread_mutex_unlock(&sl->setcallback_lock);
705 if (cb)
706 cb(cb_arg, S_SCALLBACK_REASON_CONNECTED, slot_id,
707 session_number,
708 sl->sessions[session_number].resource_id);
709 }
710
en50221_sl_handle_close_session_response(struct en50221_session_layer * sl,uint8_t * data,uint32_t data_length,uint8_t slot_id,uint8_t connection_id)711 static void en50221_sl_handle_close_session_response(struct en50221_session_layer *sl,
712 uint8_t *data,
713 uint32_t data_length,
714 uint8_t slot_id,
715 uint8_t connection_id)
716 {
717 // check
718 if (data_length < 5) {
719 print(LOG_LEVEL, ERROR, 1,
720 "Received data with invalid length from module on slot %02x\n",
721 slot_id);
722 return;
723 }
724 if (data[0] != 4) {
725 print(LOG_LEVEL, ERROR, 1,
726 "Received data with invalid length from module on slot %02x\n",
727 slot_id);
728 return;
729 }
730 // extract session number
731 uint16_t session_number = (data[2] << 8) | data[3];
732
733 // check session number is ok
734 if (session_number >= sl->max_sessions) {
735 print(LOG_LEVEL, ERROR, 1, "Received bad session id %i\n", slot_id);
736 return;
737 }
738
739 pthread_mutex_lock(&sl->sessions[session_number].session_lock);
740 if (slot_id != sl->sessions[session_number].slot_id) {
741 print(LOG_LEVEL, ERROR, 1,
742 "Received unexpected session on invalid slot %i\n",
743 slot_id);
744 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
745 return;
746 }
747 if (connection_id != sl->sessions[session_number].connection_id) {
748 print(LOG_LEVEL, ERROR, 1,
749 "Received unexpected session on invalid slot %i\n",
750 slot_id);
751 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
752 return;
753 }
754 if (sl->sessions[session_number].state != S_STATE_IN_DELETION) {
755 print(LOG_LEVEL, ERROR, 1,
756 "Received unexpected session on invalid slot %i\n",
757 slot_id);
758 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
759 return;
760 }
761 // extract status
762 if (data[1] != 0x00) {
763 print(LOG_LEVEL, ERROR, 1, "Session close failed 0x%02x\n", data[1]);
764 // just fallthrough anyway
765 }
766 // completed
767 sl->sessions[session_number].state = S_STATE_IDLE;
768 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
769 }
770
en50221_sl_handle_session_package(struct en50221_session_layer * sl,uint8_t * data,uint32_t data_length,uint8_t slot_id,uint8_t connection_id)771 static void en50221_sl_handle_session_package(struct en50221_session_layer *sl,
772 uint8_t *data,
773 uint32_t data_length,
774 uint8_t slot_id,
775 uint8_t connection_id)
776 {
777 // check
778 if (data_length < 3) {
779 print(LOG_LEVEL, ERROR, 1,
780 "Received data with invalid length from module on slot %i\n",
781 slot_id);
782 return;
783 }
784 if (data[0] != 2) {
785 print(LOG_LEVEL, ERROR, 1,
786 "Received data with invalid length from module on slot %i\n",
787 slot_id);
788 return;
789 }
790 // get session number
791 uint16_t session_number = (data[1] << 8) | data[2];
792
793 // check it
794 if (session_number >= sl->max_sessions) {
795 print(LOG_LEVEL, ERROR, 1,
796 "Received data with bad session_number from module on slot %i\n",
797 slot_id);
798 return;
799 }
800
801 pthread_mutex_lock(&sl->sessions[session_number].session_lock);
802 if (slot_id != sl->sessions[session_number].slot_id) {
803 print(LOG_LEVEL, ERROR, 1,
804 "Received unexpected session on invalid slot %i\n",
805 slot_id);
806 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
807 return;
808 }
809 if (connection_id != sl->sessions[session_number].connection_id) {
810 print(LOG_LEVEL, ERROR, 1,
811 "Received unexpected session on invalid slot %i\n",
812 slot_id);
813 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
814 return;
815 }
816 if (sl->sessions[session_number].state != S_STATE_ACTIVE) {
817 print(LOG_LEVEL, ERROR, 1,
818 "Received data with bad session_number from module on slot %i\n",
819 slot_id);
820 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
821 return;
822 }
823
824 en50221_sl_resource_callback cb = sl->sessions[session_number].callback;
825 void *cb_arg = sl->sessions[session_number].callback_arg;
826 uint32_t resource_id = sl->sessions[session_number].resource_id;
827 pthread_mutex_unlock(&sl->sessions[session_number].session_lock);
828
829 // there can be > 1 APDU following the package - all for the same session/resource_id tho.
830 data += 3;
831 data_length -= 3;
832 while (data_length) {
833 // check length field
834 if (data_length < 3) {
835 print(LOG_LEVEL, ERROR, 1,
836 "Received invalid sized session package from slot %i\n",
837 slot_id);
838 return;
839 }
840 // parse the APDU's length field
841 int length_field_len;
842 uint16_t asn_data_length;
843 if ((length_field_len = asn_1_decode(&asn_data_length, data + 3, data_length - 3)) < 0) {
844 print(LOG_LEVEL, ERROR, 1,
845 "Received invalid sized session package from slot %i\n",
846 slot_id);
847 return;
848 }
849 uint32_t apdu_length = 3 + length_field_len + asn_data_length;
850
851 // check there is enough data
852 if (apdu_length > data_length) {
853 print(LOG_LEVEL, ERROR, 1,
854 "Received invalid sized session package from slot %i\n",
855 slot_id);
856 return;
857 }
858 // pass the APDU up to the higher layers
859 if (cb)
860 cb(cb_arg, slot_id, session_number, resource_id, data, apdu_length);
861
862 // next!
863 data += apdu_length;
864 data_length -= apdu_length;
865 }
866
867 }
868
en50221_sl_transport_callback(void * arg,int reason,uint8_t * data,uint32_t data_length,uint8_t slot_id,uint8_t connection_id)869 static void en50221_sl_transport_callback(void *arg, int reason,
870 uint8_t *data,
871 uint32_t data_length,
872 uint8_t slot_id,
873 uint8_t connection_id)
874 {
875 struct en50221_session_layer *sl =
876 (struct en50221_session_layer *) arg;
877 uint32_t i;
878
879 // deal with the reason for this callback
880 switch (reason) {
881 case T_CALLBACK_REASON_DATA:
882 // fallthrough into rest of this function
883 break;
884
885 case T_CALLBACK_REASON_CONNECTIONOPEN:
886 {
887 pthread_mutex_lock(&sl->setcallback_lock);
888 en50221_sl_session_callback cb = sl->session;
889 void *cb_arg = sl->session_arg;
890 pthread_mutex_unlock(&sl->setcallback_lock);
891
892 if (cb)
893 cb(cb_arg, S_SCALLBACK_REASON_TC_CONNECT,
894 slot_id, connection_id, 0);
895 return;
896 }
897
898 case T_CALLBACK_REASON_CAMCONNECTIONOPEN:
899 {
900 pthread_mutex_lock(&sl->setcallback_lock);
901 en50221_sl_session_callback cb = sl->session;
902 void *cb_arg = sl->session_arg;
903 pthread_mutex_unlock(&sl->setcallback_lock);
904
905 if (cb)
906 cb(cb_arg,
907 S_SCALLBACK_REASON_TC_CAMCONNECT,
908 slot_id, connection_id, 0);
909 return;
910 }
911
912 case T_CALLBACK_REASON_CONNECTIONCLOSE:
913 {
914 pthread_mutex_lock(&sl->setcallback_lock);
915 en50221_sl_session_callback cb = sl->session;
916 void *cb_arg = sl->session_arg;
917 pthread_mutex_unlock(&sl->setcallback_lock);
918
919 for (i = 0; i < sl->max_sessions; i++) {
920 pthread_mutex_lock(&sl->sessions[i].session_lock);
921
922 if (sl->sessions[i].state == S_STATE_IDLE) {
923 pthread_mutex_unlock(&sl->sessions[i].session_lock);
924 continue;
925 }
926 if (sl->sessions[i].connection_id != connection_id) {
927 pthread_mutex_unlock(&sl->sessions[i].session_lock);
928 continue;
929 }
930
931 sl->sessions[i].state = S_STATE_IDLE;
932
933 uint8_t _slot_id = sl->sessions[i].slot_id;
934 uint32_t resource_id = sl->sessions[i].resource_id;
935 pthread_mutex_unlock(&sl->sessions[i].session_lock);
936
937 if (cb)
938 cb(cb_arg, S_SCALLBACK_REASON_CLOSE, _slot_id, i, resource_id);
939 }
940 return;
941 }
942
943 case T_CALLBACK_REASON_SLOTCLOSE:
944 {
945 pthread_mutex_lock(&sl->setcallback_lock);
946 en50221_sl_session_callback cb = sl->session;
947 void *cb_arg = sl->session_arg;
948 pthread_mutex_unlock(&sl->setcallback_lock);
949
950 for (i = 0; i < sl->max_sessions; i++) {
951 pthread_mutex_lock(&sl->sessions[i].session_lock);
952
953 if (sl->sessions[i].state == S_STATE_IDLE) {
954 pthread_mutex_unlock(&sl->sessions[i].session_lock);
955 continue;
956 }
957 if (sl->sessions[i].slot_id != slot_id) {
958 pthread_mutex_unlock(&sl->sessions[i].session_lock);
959 continue;
960 }
961 sl->sessions[i].state = S_STATE_IDLE;
962
963 uint32_t resource_id = sl->sessions[i].resource_id;
964 pthread_mutex_unlock(&sl->sessions[i].session_lock);
965
966 if (cb)
967 cb(cb_arg, S_SCALLBACK_REASON_CLOSE, slot_id, i, resource_id);
968
969 }
970 return;
971 }
972 }
973
974 // sanity check data length
975 if (data_length < 1) {
976 print(LOG_LEVEL, ERROR, 1,
977 "Received data with invalid length from module on slot %i\n",
978 slot_id);
979 return;
980 }
981 // deal with the data
982 uint8_t spdu_tag = data[0];
983 switch (spdu_tag) {
984 case ST_OPEN_SESSION_REQ:
985 en50221_sl_handle_open_session_request(sl, data + 1,
986 data_length - 1,
987 slot_id,
988 connection_id);
989 break;
990
991 case ST_CLOSE_SESSION_REQ:
992 en50221_sl_handle_close_session_request(sl, data + 1,
993 data_length - 1,
994 slot_id,
995 connection_id);
996 break;
997
998 case ST_SESSION_NUMBER:
999 en50221_sl_handle_session_package(sl, data + 1,
1000 data_length - 1, slot_id,
1001 connection_id);
1002 break;
1003
1004 case ST_CREATE_SESSION_RES:
1005 en50221_sl_handle_create_session_response(sl, data + 1,
1006 data_length - 1,
1007 slot_id,
1008 connection_id);
1009 break;
1010
1011 case ST_CLOSE_SESSION_RES:
1012 en50221_sl_handle_close_session_response(sl, data + 1,
1013 data_length - 1,
1014 slot_id,
1015 connection_id);
1016 break;
1017
1018 default:
1019 print(LOG_LEVEL, ERROR, 1,
1020 "Received unknown session tag %02x from module on slot %i",
1021 spdu_tag, slot_id);
1022 break;
1023 }
1024 }
1025
en50221_sl_alloc_new_session(struct en50221_session_layer * sl,uint32_t resource_id,uint8_t slot_id,uint8_t connection_id,en50221_sl_resource_callback callback,void * arg)1026 static int en50221_sl_alloc_new_session(struct en50221_session_layer *sl,
1027 uint32_t resource_id,
1028 uint8_t slot_id,
1029 uint8_t connection_id,
1030 en50221_sl_resource_callback
1031 callback, void *arg)
1032 {
1033 int session_number = -1;
1034 uint32_t i;
1035 for (i = 1; i < sl->max_sessions; i++) {
1036 if (sl->sessions[i].state == S_STATE_IDLE) {
1037 session_number = i;
1038 break;
1039 }
1040 }
1041 if (session_number == -1) {
1042 sl->error = EN50221ERR_OUTOFSESSIONS;
1043 return -1;
1044 }
1045 // setup the session
1046 sl->sessions[session_number].state = S_STATE_IN_CREATION;
1047 sl->sessions[session_number].resource_id = resource_id;
1048 sl->sessions[session_number].slot_id = slot_id;
1049 sl->sessions[session_number].connection_id = connection_id;
1050 sl->sessions[session_number].callback = callback;
1051 sl->sessions[session_number].callback_arg = arg;
1052
1053 // ok
1054 return session_number;
1055 }
1056