1 /*
2    CMTP implementation for Linux Bluetooth stack (BlueZ).
3    Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License version 2 as
7    published by the Free Software Foundation;
8 
9    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13    CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 
18    ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19    COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20    SOFTWARE IS DISCLAIMED.
21 */
22 
23 #include <linux/export.h>
24 #include <linux/proc_fs.h>
25 #include <linux/seq_file.h>
26 #include <linux/types.h>
27 #include <linux/errno.h>
28 #include <linux/kernel.h>
29 #include <linux/sched/signal.h>
30 #include <linux/slab.h>
31 #include <linux/poll.h>
32 #include <linux/fcntl.h>
33 #include <linux/skbuff.h>
34 #include <linux/socket.h>
35 #include <linux/ioctl.h>
36 #include <linux/file.h>
37 #include <linux/wait.h>
38 #include <linux/kthread.h>
39 #include <net/sock.h>
40 
41 #include <linux/isdn/capilli.h>
42 #include <linux/isdn/capicmd.h>
43 #include <linux/isdn/capiutil.h>
44 
45 #include "cmtp.h"
46 
47 #define CAPI_INTEROPERABILITY		0x20
48 
49 #define CAPI_INTEROPERABILITY_REQ	CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
50 #define CAPI_INTEROPERABILITY_CONF	CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
51 #define CAPI_INTEROPERABILITY_IND	CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
52 #define CAPI_INTEROPERABILITY_RESP	CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
53 
54 #define CAPI_INTEROPERABILITY_REQ_LEN	(CAPI_MSG_BASELEN + 2)
55 #define CAPI_INTEROPERABILITY_CONF_LEN	(CAPI_MSG_BASELEN + 4)
56 #define CAPI_INTEROPERABILITY_IND_LEN	(CAPI_MSG_BASELEN + 2)
57 #define CAPI_INTEROPERABILITY_RESP_LEN	(CAPI_MSG_BASELEN + 2)
58 
59 #define CAPI_FUNCTION_REGISTER		0
60 #define CAPI_FUNCTION_RELEASE		1
61 #define CAPI_FUNCTION_GET_PROFILE	2
62 #define CAPI_FUNCTION_GET_MANUFACTURER	3
63 #define CAPI_FUNCTION_GET_VERSION	4
64 #define CAPI_FUNCTION_GET_SERIAL_NUMBER	5
65 #define CAPI_FUNCTION_MANUFACTURER	6
66 #define CAPI_FUNCTION_LOOPBACK		7
67 
68 
69 #define CMTP_MSGNUM	1
70 #define CMTP_APPLID	2
71 #define CMTP_MAPPING	3
72 
cmtp_application_add(struct cmtp_session * session,__u16 appl)73 static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
74 {
75 	struct cmtp_application *app = kzalloc(sizeof(*app), GFP_KERNEL);
76 
77 	BT_DBG("session %p application %p appl %d", session, app, appl);
78 
79 	if (!app)
80 		return NULL;
81 
82 	app->state = BT_OPEN;
83 	app->appl = appl;
84 
85 	list_add_tail(&app->list, &session->applications);
86 
87 	return app;
88 }
89 
cmtp_application_del(struct cmtp_session * session,struct cmtp_application * app)90 static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
91 {
92 	BT_DBG("session %p application %p", session, app);
93 
94 	if (app) {
95 		list_del(&app->list);
96 		kfree(app);
97 	}
98 }
99 
cmtp_application_get(struct cmtp_session * session,int pattern,__u16 value)100 static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
101 {
102 	struct cmtp_application *app;
103 
104 	list_for_each_entry(app, &session->applications, list) {
105 		switch (pattern) {
106 		case CMTP_MSGNUM:
107 			if (app->msgnum == value)
108 				return app;
109 			break;
110 		case CMTP_APPLID:
111 			if (app->appl == value)
112 				return app;
113 			break;
114 		case CMTP_MAPPING:
115 			if (app->mapping == value)
116 				return app;
117 			break;
118 		}
119 	}
120 
121 	return NULL;
122 }
123 
cmtp_msgnum_get(struct cmtp_session * session)124 static int cmtp_msgnum_get(struct cmtp_session *session)
125 {
126 	session->msgnum++;
127 
128 	if ((session->msgnum & 0xff) > 200)
129 		session->msgnum = CMTP_INITIAL_MSGNUM + 1;
130 
131 	return session->msgnum;
132 }
133 
cmtp_send_capimsg(struct cmtp_session * session,struct sk_buff * skb)134 static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
135 {
136 	struct cmtp_scb *scb = (void *) skb->cb;
137 
138 	BT_DBG("session %p skb %p len %d", session, skb, skb->len);
139 
140 	scb->id = -1;
141 	scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
142 
143 	skb_queue_tail(&session->transmit, skb);
144 
145 	wake_up_interruptible(sk_sleep(session->sock->sk));
146 }
147 
cmtp_send_interopmsg(struct cmtp_session * session,__u8 subcmd,__u16 appl,__u16 msgnum,__u16 function,unsigned char * buf,int len)148 static void cmtp_send_interopmsg(struct cmtp_session *session,
149 					__u8 subcmd, __u16 appl, __u16 msgnum,
150 					__u16 function, unsigned char *buf, int len)
151 {
152 	struct sk_buff *skb;
153 	unsigned char *s;
154 
155 	BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
156 
157 	skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC);
158 	if (!skb) {
159 		BT_ERR("Can't allocate memory for interoperability packet");
160 		return;
161 	}
162 
163 	s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
164 
165 	capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
166 	capimsg_setu16(s, 2, appl);
167 	capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
168 	capimsg_setu8 (s, 5, subcmd);
169 	capimsg_setu16(s, 6, msgnum);
170 
171 	/* Interoperability selector (Bluetooth Device Management) */
172 	capimsg_setu16(s, 8, 0x0001);
173 
174 	capimsg_setu8 (s, 10, 3 + len);
175 	capimsg_setu16(s, 11, function);
176 	capimsg_setu8 (s, 13, len);
177 
178 	if (len > 0)
179 		memcpy(s + 14, buf, len);
180 
181 	cmtp_send_capimsg(session, skb);
182 }
183 
cmtp_recv_interopmsg(struct cmtp_session * session,struct sk_buff * skb)184 static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
185 {
186 	struct capi_ctr *ctrl = &session->ctrl;
187 	struct cmtp_application *application;
188 	__u16 appl, msgnum, func, info;
189 	__u32 controller;
190 
191 	BT_DBG("session %p skb %p len %d", session, skb, skb->len);
192 
193 	switch (CAPIMSG_SUBCOMMAND(skb->data)) {
194 	case CAPI_CONF:
195 		if (skb->len < CAPI_MSG_BASELEN + 10)
196 			break;
197 
198 		func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
199 		info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
200 
201 		switch (func) {
202 		case CAPI_FUNCTION_REGISTER:
203 			msgnum = CAPIMSG_MSGID(skb->data);
204 
205 			application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
206 			if (application) {
207 				application->state = BT_CONNECTED;
208 				application->msgnum = 0;
209 				application->mapping = CAPIMSG_APPID(skb->data);
210 				wake_up_interruptible(&session->wait);
211 			}
212 
213 			break;
214 
215 		case CAPI_FUNCTION_RELEASE:
216 			appl = CAPIMSG_APPID(skb->data);
217 
218 			application = cmtp_application_get(session, CMTP_MAPPING, appl);
219 			if (application) {
220 				application->state = BT_CLOSED;
221 				application->msgnum = 0;
222 				wake_up_interruptible(&session->wait);
223 			}
224 
225 			break;
226 
227 		case CAPI_FUNCTION_GET_PROFILE:
228 			if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile))
229 				break;
230 
231 			controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
232 			msgnum = CAPIMSG_MSGID(skb->data);
233 
234 			if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
235 				session->ncontroller = controller;
236 				wake_up_interruptible(&session->wait);
237 				break;
238 			}
239 
240 			if (!info && ctrl) {
241 				memcpy(&ctrl->profile,
242 					skb->data + CAPI_MSG_BASELEN + 11,
243 					sizeof(capi_profile));
244 				session->state = BT_CONNECTED;
245 				capi_ctr_ready(ctrl);
246 			}
247 
248 			break;
249 
250 		case CAPI_FUNCTION_GET_MANUFACTURER:
251 			if (skb->len < CAPI_MSG_BASELEN + 15)
252 				break;
253 
254 			if (!info && ctrl) {
255 				int len = min_t(uint, CAPI_MANUFACTURER_LEN,
256 						skb->data[CAPI_MSG_BASELEN + 14]);
257 
258 				memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
259 				strncpy(ctrl->manu,
260 					skb->data + CAPI_MSG_BASELEN + 15, len);
261 			}
262 
263 			break;
264 
265 		case CAPI_FUNCTION_GET_VERSION:
266 			if (skb->len < CAPI_MSG_BASELEN + 32)
267 				break;
268 
269 			if (!info && ctrl) {
270 				ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
271 				ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
272 				ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
273 				ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
274 			}
275 
276 			break;
277 
278 		case CAPI_FUNCTION_GET_SERIAL_NUMBER:
279 			if (skb->len < CAPI_MSG_BASELEN + 17)
280 				break;
281 
282 			if (!info && ctrl) {
283 				int len = min_t(uint, CAPI_SERIAL_LEN,
284 						skb->data[CAPI_MSG_BASELEN + 16]);
285 
286 				memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
287 				strncpy(ctrl->serial,
288 					skb->data + CAPI_MSG_BASELEN + 17, len);
289 			}
290 
291 			break;
292 		}
293 
294 		break;
295 
296 	case CAPI_IND:
297 		if (skb->len < CAPI_MSG_BASELEN + 6)
298 			break;
299 
300 		func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
301 
302 		if (func == CAPI_FUNCTION_LOOPBACK) {
303 			int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
304 						skb->data[CAPI_MSG_BASELEN + 5]);
305 			appl = CAPIMSG_APPID(skb->data);
306 			msgnum = CAPIMSG_MSGID(skb->data);
307 			cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
308 						skb->data + CAPI_MSG_BASELEN + 6, len);
309 		}
310 
311 		break;
312 	}
313 
314 	kfree_skb(skb);
315 }
316 
cmtp_recv_capimsg(struct cmtp_session * session,struct sk_buff * skb)317 void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
318 {
319 	struct capi_ctr *ctrl = &session->ctrl;
320 	struct cmtp_application *application;
321 	__u16 appl;
322 	__u32 contr;
323 
324 	BT_DBG("session %p skb %p len %d", session, skb, skb->len);
325 
326 	if (skb->len < CAPI_MSG_BASELEN)
327 		return;
328 
329 	if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
330 		cmtp_recv_interopmsg(session, skb);
331 		return;
332 	}
333 
334 	if (session->flags & BIT(CMTP_LOOPBACK)) {
335 		kfree_skb(skb);
336 		return;
337 	}
338 
339 	appl = CAPIMSG_APPID(skb->data);
340 	contr = CAPIMSG_CONTROL(skb->data);
341 
342 	application = cmtp_application_get(session, CMTP_MAPPING, appl);
343 	if (application) {
344 		appl = application->appl;
345 		CAPIMSG_SETAPPID(skb->data, appl);
346 	} else {
347 		BT_ERR("Can't find application with id %d", appl);
348 		kfree_skb(skb);
349 		return;
350 	}
351 
352 	if ((contr & 0x7f) == 0x01) {
353 		contr = (contr & 0xffffff80) | session->num;
354 		CAPIMSG_SETCONTROL(skb->data, contr);
355 	}
356 
357 	capi_ctr_handle_message(ctrl, appl, skb);
358 }
359 
cmtp_load_firmware(struct capi_ctr * ctrl,capiloaddata * data)360 static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
361 {
362 	BT_DBG("ctrl %p data %p", ctrl, data);
363 
364 	return 0;
365 }
366 
cmtp_reset_ctr(struct capi_ctr * ctrl)367 static void cmtp_reset_ctr(struct capi_ctr *ctrl)
368 {
369 	struct cmtp_session *session = ctrl->driverdata;
370 
371 	BT_DBG("ctrl %p", ctrl);
372 
373 	capi_ctr_down(ctrl);
374 
375 	atomic_inc(&session->terminate);
376 	wake_up_process(session->task);
377 }
378 
cmtp_register_appl(struct capi_ctr * ctrl,__u16 appl,capi_register_params * rp)379 static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
380 {
381 	DECLARE_WAITQUEUE(wait, current);
382 	struct cmtp_session *session = ctrl->driverdata;
383 	struct cmtp_application *application;
384 	unsigned long timeo = CMTP_INTEROP_TIMEOUT;
385 	unsigned char buf[8];
386 	int err = 0, nconn, want = rp->level3cnt;
387 
388 	BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
389 		ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
390 
391 	application = cmtp_application_add(session, appl);
392 	if (!application) {
393 		BT_ERR("Can't allocate memory for new application");
394 		return;
395 	}
396 
397 	if (want < 0)
398 		nconn = ctrl->profile.nbchannel * -want;
399 	else
400 		nconn = want;
401 
402 	if (nconn == 0)
403 		nconn = ctrl->profile.nbchannel;
404 
405 	capimsg_setu16(buf, 0, nconn);
406 	capimsg_setu16(buf, 2, rp->datablkcnt);
407 	capimsg_setu16(buf, 4, rp->datablklen);
408 
409 	application->state = BT_CONFIG;
410 	application->msgnum = cmtp_msgnum_get(session);
411 
412 	cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
413 				CAPI_FUNCTION_REGISTER, buf, 6);
414 
415 	add_wait_queue(&session->wait, &wait);
416 	while (1) {
417 		set_current_state(TASK_INTERRUPTIBLE);
418 
419 		if (!timeo) {
420 			err = -EAGAIN;
421 			break;
422 		}
423 
424 		if (application->state == BT_CLOSED) {
425 			err = -application->err;
426 			break;
427 		}
428 
429 		if (application->state == BT_CONNECTED)
430 			break;
431 
432 		if (signal_pending(current)) {
433 			err = -EINTR;
434 			break;
435 		}
436 
437 		timeo = schedule_timeout(timeo);
438 	}
439 	set_current_state(TASK_RUNNING);
440 	remove_wait_queue(&session->wait, &wait);
441 
442 	if (err) {
443 		cmtp_application_del(session, application);
444 		return;
445 	}
446 }
447 
cmtp_release_appl(struct capi_ctr * ctrl,__u16 appl)448 static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
449 {
450 	struct cmtp_session *session = ctrl->driverdata;
451 	struct cmtp_application *application;
452 
453 	BT_DBG("ctrl %p appl %d", ctrl, appl);
454 
455 	application = cmtp_application_get(session, CMTP_APPLID, appl);
456 	if (!application) {
457 		BT_ERR("Can't find application");
458 		return;
459 	}
460 
461 	application->msgnum = cmtp_msgnum_get(session);
462 
463 	cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
464 				CAPI_FUNCTION_RELEASE, NULL, 0);
465 
466 	wait_event_interruptible_timeout(session->wait,
467 			(application->state == BT_CLOSED), CMTP_INTEROP_TIMEOUT);
468 
469 	cmtp_application_del(session, application);
470 }
471 
cmtp_send_message(struct capi_ctr * ctrl,struct sk_buff * skb)472 static u16 cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
473 {
474 	struct cmtp_session *session = ctrl->driverdata;
475 	struct cmtp_application *application;
476 	__u16 appl;
477 	__u32 contr;
478 
479 	BT_DBG("ctrl %p skb %p", ctrl, skb);
480 
481 	appl = CAPIMSG_APPID(skb->data);
482 	contr = CAPIMSG_CONTROL(skb->data);
483 
484 	application = cmtp_application_get(session, CMTP_APPLID, appl);
485 	if ((!application) || (application->state != BT_CONNECTED)) {
486 		BT_ERR("Can't find application with id %d", appl);
487 		return CAPI_ILLAPPNR;
488 	}
489 
490 	CAPIMSG_SETAPPID(skb->data, application->mapping);
491 
492 	if ((contr & 0x7f) == session->num) {
493 		contr = (contr & 0xffffff80) | 0x01;
494 		CAPIMSG_SETCONTROL(skb->data, contr);
495 	}
496 
497 	cmtp_send_capimsg(session, skb);
498 
499 	return CAPI_NOERROR;
500 }
501 
cmtp_procinfo(struct capi_ctr * ctrl)502 static char *cmtp_procinfo(struct capi_ctr *ctrl)
503 {
504 	return "CAPI Message Transport Protocol";
505 }
506 
cmtp_proc_show(struct seq_file * m,void * v)507 static int cmtp_proc_show(struct seq_file *m, void *v)
508 {
509 	struct capi_ctr *ctrl = m->private;
510 	struct cmtp_session *session = ctrl->driverdata;
511 	struct cmtp_application *app;
512 
513 	seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
514 	seq_printf(m, "addr %s\n", session->name);
515 	seq_printf(m, "ctrl %d\n", session->num);
516 
517 	list_for_each_entry(app, &session->applications, list) {
518 		seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping);
519 	}
520 
521 	return 0;
522 }
523 
cmtp_attach_device(struct cmtp_session * session)524 int cmtp_attach_device(struct cmtp_session *session)
525 {
526 	unsigned char buf[4];
527 	long ret;
528 
529 	BT_DBG("session %p", session);
530 
531 	capimsg_setu32(buf, 0, 0);
532 
533 	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
534 				CAPI_FUNCTION_GET_PROFILE, buf, 4);
535 
536 	ret = wait_event_interruptible_timeout(session->wait,
537 			session->ncontroller, CMTP_INTEROP_TIMEOUT);
538 
539 	BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
540 
541 	if (!ret)
542 		return -ETIMEDOUT;
543 
544 	if (!session->ncontroller)
545 		return -ENODEV;
546 
547 	if (session->ncontroller > 1)
548 		BT_INFO("Setting up only CAPI controller 1");
549 
550 	session->ctrl.owner      = THIS_MODULE;
551 	session->ctrl.driverdata = session;
552 	strcpy(session->ctrl.name, session->name);
553 
554 	session->ctrl.driver_name   = "cmtp";
555 	session->ctrl.load_firmware = cmtp_load_firmware;
556 	session->ctrl.reset_ctr     = cmtp_reset_ctr;
557 	session->ctrl.register_appl = cmtp_register_appl;
558 	session->ctrl.release_appl  = cmtp_release_appl;
559 	session->ctrl.send_message  = cmtp_send_message;
560 
561 	session->ctrl.procinfo      = cmtp_procinfo;
562 	session->ctrl.proc_show     = cmtp_proc_show;
563 
564 	if (attach_capi_ctr(&session->ctrl) < 0) {
565 		BT_ERR("Can't attach new controller");
566 		return -EBUSY;
567 	}
568 
569 	session->num = session->ctrl.cnr;
570 
571 	BT_DBG("session %p num %d", session, session->num);
572 
573 	capimsg_setu32(buf, 0, 1);
574 
575 	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
576 				CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
577 
578 	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
579 				CAPI_FUNCTION_GET_VERSION, buf, 4);
580 
581 	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
582 				CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
583 
584 	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
585 				CAPI_FUNCTION_GET_PROFILE, buf, 4);
586 
587 	return 0;
588 }
589 
cmtp_detach_device(struct cmtp_session * session)590 void cmtp_detach_device(struct cmtp_session *session)
591 {
592 	BT_DBG("session %p", session);
593 
594 	detach_capi_ctr(&session->ctrl);
595 }
596