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