1 /* hfp_hf.c - Hands free Profile - Handsfree side handling */
2 
3 /*
4  * Copyright (c) 2015-2016 Intel Corporation
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 #include <zephyr/kernel.h>
9 #include <errno.h>
10 #include <zephyr/sys/atomic.h>
11 #include <zephyr/sys/byteorder.h>
12 #include <zephyr/sys/util.h>
13 #include <zephyr/sys/printk.h>
14 
15 #include <zephyr/bluetooth/conn.h>
16 
17 #include "common/assert.h"
18 
19 #include <zephyr/bluetooth/rfcomm.h>
20 #include <zephyr/bluetooth/hfp_hf.h>
21 
22 #include "hci_core.h"
23 #include "conn_internal.h"
24 #include "l2cap_internal.h"
25 #include "rfcomm_internal.h"
26 #include "at.h"
27 #include "hfp_internal.h"
28 
29 #define LOG_LEVEL CONFIG_BT_HFP_HF_LOG_LEVEL
30 #include <zephyr/logging/log.h>
31 LOG_MODULE_REGISTER(bt_hfp_hf);
32 
33 #define MAX_IND_STR_LEN 17
34 
35 struct bt_hfp_hf_cb *bt_hf;
36 
37 NET_BUF_POOL_FIXED_DEFINE(hf_pool, CONFIG_BT_MAX_CONN + 1,
38 			  BT_RFCOMM_BUF_SIZE(BT_HF_CLIENT_MAX_PDU), 8, NULL);
39 
40 static struct bt_hfp_hf bt_hfp_hf_pool[CONFIG_BT_MAX_CONN];
41 
42 /* The order should follow the enum hfp_hf_ag_indicators */
43 static const struct {
44 	char *name;
45 	uint32_t min;
46 	uint32_t max;
47 } ag_ind[] = {
48 	{"service", 0, 1}, /* HF_SERVICE_IND */
49 	{"call", 0, 1}, /* HF_CALL_IND */
50 	{"callsetup", 0, 3}, /* HF_CALL_SETUP_IND */
51 	{"callheld", 0, 2}, /* HF_CALL_HELD_IND */
52 	{"signal", 0, 5}, /* HF_SIGNAL_IND */
53 	{"roam", 0, 1}, /* HF_ROAM_IND */
54 	{"battchg", 0, 5} /* HF_BATTERY_IND */
55 };
56 
hf_slc_error(struct at_client * hf_at)57 void hf_slc_error(struct at_client *hf_at)
58 {
59 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
60 	int err;
61 
62 	LOG_ERR("SLC error: disconnecting");
63 	err = bt_rfcomm_dlc_disconnect(&hf->rfcomm_dlc);
64 	if (err) {
65 		LOG_ERR("Rfcomm: Unable to disconnect :%d", -err);
66 	}
67 }
68 
hfp_hf_send_cmd(struct bt_hfp_hf * hf,at_resp_cb_t resp,at_finish_cb_t finish,const char * format,...)69 int hfp_hf_send_cmd(struct bt_hfp_hf *hf, at_resp_cb_t resp,
70 		    at_finish_cb_t finish, const char *format, ...)
71 {
72 	struct net_buf *buf;
73 	va_list vargs;
74 	int ret;
75 
76 	/* register the callbacks */
77 	at_register(&hf->at, resp, finish);
78 
79 	buf = bt_rfcomm_create_pdu(&hf_pool);
80 	if (!buf) {
81 		LOG_ERR("No Buffers!");
82 		return -ENOMEM;
83 	}
84 
85 	va_start(vargs, format);
86 	ret = vsnprintk(buf->data, (net_buf_tailroom(buf) - 1), format, vargs);
87 	if (ret < 0) {
88 		LOG_ERR("Unable to format variable arguments");
89 		return ret;
90 	}
91 	va_end(vargs);
92 
93 	net_buf_add(buf, ret);
94 	net_buf_add_u8(buf, '\r');
95 
96 	ret = bt_rfcomm_dlc_send(&hf->rfcomm_dlc, buf);
97 	if (ret < 0) {
98 		LOG_ERR("Rfcomm send error :(%d)", ret);
99 		return ret;
100 	}
101 
102 	return 0;
103 }
104 
brsf_handle(struct at_client * hf_at)105 int brsf_handle(struct at_client *hf_at)
106 {
107 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
108 	uint32_t val;
109 	int ret;
110 
111 	ret = at_get_number(hf_at, &val);
112 	if (ret < 0) {
113 		LOG_ERR("Error getting value");
114 		return ret;
115 	}
116 
117 	hf->ag_features = val;
118 
119 	return 0;
120 }
121 
brsf_resp(struct at_client * hf_at,struct net_buf * buf)122 int brsf_resp(struct at_client *hf_at, struct net_buf *buf)
123 {
124 	int err;
125 
126 	LOG_DBG("");
127 
128 	err = at_parse_cmd_input(hf_at, buf, "BRSF", brsf_handle,
129 				 AT_CMD_TYPE_NORMAL);
130 	if (err < 0) {
131 		/* Returning negative value is avoided before SLC connection
132 		 * established.
133 		 */
134 		LOG_ERR("Error parsing CMD input");
135 		hf_slc_error(hf_at);
136 	}
137 
138 	return 0;
139 }
140 
cind_handle_values(struct at_client * hf_at,uint32_t index,char * name,uint32_t min,uint32_t max)141 static void cind_handle_values(struct at_client *hf_at, uint32_t index,
142 			       char *name, uint32_t min, uint32_t max)
143 {
144 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
145 	int i;
146 
147 	LOG_DBG("index: %u, name: %s, min: %u, max:%u", index, name, min, max);
148 
149 	for (i = 0; i < ARRAY_SIZE(ag_ind); i++) {
150 		if (strcmp(name, ag_ind[i].name) != 0) {
151 			continue;
152 		}
153 		if (min != ag_ind[i].min || max != ag_ind[i].max) {
154 			LOG_ERR("%s indicator min/max value not matching", name);
155 		}
156 
157 		hf->ind_table[index] = i;
158 		break;
159 	}
160 }
161 
cind_handle(struct at_client * hf_at)162 int cind_handle(struct at_client *hf_at)
163 {
164 	uint32_t index = 0U;
165 
166 	/* Parsing Example: CIND: ("call",(0,1)) etc.. */
167 	while (at_has_next_list(hf_at)) {
168 		char name[MAX_IND_STR_LEN];
169 		uint32_t min, max;
170 
171 		if (at_open_list(hf_at) < 0) {
172 			LOG_ERR("Could not get open list");
173 			goto error;
174 		}
175 
176 		if (at_list_get_string(hf_at, name, sizeof(name)) < 0) {
177 			LOG_ERR("Could not get string");
178 			goto error;
179 		}
180 
181 		if (at_open_list(hf_at) < 0) {
182 			LOG_ERR("Could not get open list");
183 			goto error;
184 		}
185 
186 		if (at_list_get_range(hf_at, &min, &max) < 0) {
187 			LOG_ERR("Could not get range");
188 			goto error;
189 		}
190 
191 		if (at_close_list(hf_at) < 0) {
192 			LOG_ERR("Could not get close list");
193 			goto error;
194 		}
195 
196 		if (at_close_list(hf_at) < 0) {
197 			LOG_ERR("Could not get close list");
198 			goto error;
199 		}
200 
201 		cind_handle_values(hf_at, index, name, min, max);
202 		index++;
203 	}
204 
205 	return 0;
206 error:
207 	LOG_ERR("Error on CIND response");
208 	hf_slc_error(hf_at);
209 	return -EINVAL;
210 }
211 
cind_resp(struct at_client * hf_at,struct net_buf * buf)212 int cind_resp(struct at_client *hf_at, struct net_buf *buf)
213 {
214 	int err;
215 
216 	err = at_parse_cmd_input(hf_at, buf, "CIND", cind_handle,
217 				 AT_CMD_TYPE_NORMAL);
218 	if (err < 0) {
219 		LOG_ERR("Error parsing CMD input");
220 		hf_slc_error(hf_at);
221 	}
222 
223 	return 0;
224 }
225 
ag_indicator_handle_values(struct at_client * hf_at,uint32_t index,uint32_t value)226 void ag_indicator_handle_values(struct at_client *hf_at, uint32_t index,
227 				uint32_t value)
228 {
229 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
230 	struct bt_conn *conn = hf->rfcomm_dlc.session->br_chan.chan.conn;
231 
232 	LOG_DBG("Index :%u, Value :%u", index, value);
233 
234 	if (index >= ARRAY_SIZE(ag_ind)) {
235 		LOG_ERR("Max only %zu indicators are supported", ARRAY_SIZE(ag_ind));
236 		return;
237 	}
238 
239 	if (value > ag_ind[hf->ind_table[index]].max ||
240 	    value < ag_ind[hf->ind_table[index]].min) {
241 		LOG_ERR("Indicators out of range - value: %u", value);
242 		return;
243 	}
244 
245 	switch (hf->ind_table[index]) {
246 	case HF_SERVICE_IND:
247 		if (bt_hf->service) {
248 			bt_hf->service(conn, value);
249 		}
250 		break;
251 	case HF_CALL_IND:
252 		if (bt_hf->call) {
253 			bt_hf->call(conn, value);
254 		}
255 		break;
256 	case HF_CALL_SETUP_IND:
257 		if (bt_hf->call_setup) {
258 			bt_hf->call_setup(conn, value);
259 		}
260 		break;
261 	case HF_CALL_HELD_IND:
262 		if (bt_hf->call_held) {
263 			bt_hf->call_held(conn, value);
264 		}
265 		break;
266 	case HF_SINGNAL_IND:
267 		if (bt_hf->signal) {
268 			bt_hf->signal(conn, value);
269 		}
270 		break;
271 	case HF_ROAM_IND:
272 		if (bt_hf->roam) {
273 			bt_hf->roam(conn, value);
274 		}
275 		break;
276 	case HF_BATTERY_IND:
277 		if (bt_hf->battery) {
278 			bt_hf->battery(conn, value);
279 		}
280 		break;
281 	default:
282 		LOG_ERR("Unknown AG indicator");
283 		break;
284 	}
285 }
286 
cind_status_handle(struct at_client * hf_at)287 int cind_status_handle(struct at_client *hf_at)
288 {
289 	uint32_t index = 0U;
290 
291 	while (at_has_next_list(hf_at)) {
292 		uint32_t value;
293 		int ret;
294 
295 		ret = at_get_number(hf_at, &value);
296 		if (ret < 0) {
297 			LOG_ERR("could not get the value");
298 			return ret;
299 		}
300 
301 		ag_indicator_handle_values(hf_at, index, value);
302 
303 		index++;
304 	}
305 
306 	return 0;
307 }
308 
cind_status_resp(struct at_client * hf_at,struct net_buf * buf)309 int cind_status_resp(struct at_client *hf_at, struct net_buf *buf)
310 {
311 	int err;
312 
313 	err = at_parse_cmd_input(hf_at, buf, "CIND", cind_status_handle,
314 				 AT_CMD_TYPE_NORMAL);
315 	if (err < 0) {
316 		LOG_ERR("Error parsing CMD input");
317 		hf_slc_error(hf_at);
318 	}
319 
320 	return 0;
321 }
322 
ciev_handle(struct at_client * hf_at)323 int ciev_handle(struct at_client *hf_at)
324 {
325 	uint32_t index, value;
326 	int ret;
327 
328 	ret = at_get_number(hf_at, &index);
329 	if (ret < 0) {
330 		LOG_ERR("could not get the Index");
331 		return ret;
332 	}
333 	/* The first element of the list shall have 1 */
334 	if (!index) {
335 		LOG_ERR("Invalid index value '0'");
336 		return 0;
337 	}
338 
339 	ret = at_get_number(hf_at, &value);
340 	if (ret < 0) {
341 		LOG_ERR("could not get the value");
342 		return ret;
343 	}
344 
345 	ag_indicator_handle_values(hf_at, (index - 1), value);
346 
347 	return 0;
348 }
349 
ring_handle(struct at_client * hf_at)350 int ring_handle(struct at_client *hf_at)
351 {
352 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
353 	struct bt_conn *conn = hf->rfcomm_dlc.session->br_chan.chan.conn;
354 
355 	if (bt_hf->ring_indication) {
356 		bt_hf->ring_indication(conn);
357 	}
358 
359 	return 0;
360 }
361 
362 static const struct unsolicited {
363 	const char *cmd;
364 	enum at_cmd_type type;
365 	int (*func)(struct at_client *hf_at);
366 } handlers[] = {
367 	{ "CIEV", AT_CMD_TYPE_UNSOLICITED, ciev_handle },
368 	{ "RING", AT_CMD_TYPE_OTHER, ring_handle }
369 };
370 
hfp_hf_unsol_lookup(struct at_client * hf_at)371 static const struct unsolicited *hfp_hf_unsol_lookup(struct at_client *hf_at)
372 {
373 	int i;
374 
375 	for (i = 0; i < ARRAY_SIZE(handlers); i++) {
376 		if (!strncmp(hf_at->buf, handlers[i].cmd,
377 			     strlen(handlers[i].cmd))) {
378 			return &handlers[i];
379 		}
380 	}
381 
382 	return NULL;
383 }
384 
unsolicited_cb(struct at_client * hf_at,struct net_buf * buf)385 int unsolicited_cb(struct at_client *hf_at, struct net_buf *buf)
386 {
387 	const struct unsolicited *handler;
388 
389 	handler = hfp_hf_unsol_lookup(hf_at);
390 	if (!handler) {
391 		LOG_ERR("Unhandled unsolicited response");
392 		return -ENOMSG;
393 	}
394 
395 	if (!at_parse_cmd_input(hf_at, buf, handler->cmd, handler->func,
396 				handler->type)) {
397 		return 0;
398 	}
399 
400 	return -ENOMSG;
401 }
402 
cmd_complete(struct at_client * hf_at,enum at_result result,enum at_cme cme_err)403 int cmd_complete(struct at_client *hf_at, enum at_result result,
404 	       enum at_cme cme_err)
405 {
406 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
407 	struct bt_conn *conn = hf->rfcomm_dlc.session->br_chan.chan.conn;
408 	struct bt_hfp_hf_cmd_complete cmd = { 0 };
409 
410 	LOG_DBG("");
411 
412 	switch (result) {
413 	case AT_RESULT_OK:
414 		cmd.type = HFP_HF_CMD_OK;
415 		break;
416 	case AT_RESULT_ERROR:
417 		cmd.type = HFP_HF_CMD_ERROR;
418 		break;
419 	case AT_RESULT_CME_ERROR:
420 		cmd.type = HFP_HF_CMD_CME_ERROR;
421 		cmd.cme = cme_err;
422 		break;
423 	default:
424 		LOG_ERR("Unknown error code");
425 		cmd.type = HFP_HF_CMD_UNKNOWN_ERROR;
426 		break;
427 	}
428 
429 	if (bt_hf->cmd_complete_cb) {
430 		bt_hf->cmd_complete_cb(conn, &cmd);
431 	}
432 
433 	return 0;
434 }
435 
cmee_finish(struct at_client * hf_at,enum at_result result,enum at_cme cme_err)436 int cmee_finish(struct at_client *hf_at, enum at_result result,
437 		enum at_cme cme_err)
438 {
439 	if (result != AT_RESULT_OK) {
440 		LOG_ERR("SLC Connection ERROR in response");
441 		return -EINVAL;
442 	}
443 
444 	return 0;
445 }
446 
slc_completed(struct at_client * hf_at)447 static void slc_completed(struct at_client *hf_at)
448 {
449 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
450 	struct bt_conn *conn = hf->rfcomm_dlc.session->br_chan.chan.conn;
451 
452 	if (bt_hf->connected) {
453 		bt_hf->connected(conn);
454 	}
455 
456 	if (hfp_hf_send_cmd(hf, NULL, cmee_finish, "AT+CMEE=1") < 0) {
457 		LOG_ERR("Error Sending AT+CMEE");
458 	}
459 }
460 
cmer_finish(struct at_client * hf_at,enum at_result result,enum at_cme cme_err)461 int cmer_finish(struct at_client *hf_at, enum at_result result,
462 		enum at_cme cme_err)
463 {
464 	if (result != AT_RESULT_OK) {
465 		LOG_ERR("SLC Connection ERROR in response");
466 		hf_slc_error(hf_at);
467 		return -EINVAL;
468 	}
469 
470 	slc_completed(hf_at);
471 
472 	return 0;
473 }
474 
cind_status_finish(struct at_client * hf_at,enum at_result result,enum at_cme cme_err)475 int cind_status_finish(struct at_client *hf_at, enum at_result result,
476 		       enum at_cme cme_err)
477 {
478 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
479 	int err;
480 
481 	if (result != AT_RESULT_OK) {
482 		LOG_ERR("SLC Connection ERROR in response");
483 		hf_slc_error(hf_at);
484 		return -EINVAL;
485 	}
486 
487 	at_register_unsolicited(hf_at, unsolicited_cb);
488 	err = hfp_hf_send_cmd(hf, NULL, cmer_finish, "AT+CMER=3,0,0,1");
489 	if (err < 0) {
490 		hf_slc_error(hf_at);
491 		return err;
492 	}
493 
494 	return 0;
495 }
496 
cind_finish(struct at_client * hf_at,enum at_result result,enum at_cme cme_err)497 int cind_finish(struct at_client *hf_at, enum at_result result,
498 		enum at_cme cme_err)
499 {
500 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
501 	int err;
502 
503 	if (result != AT_RESULT_OK) {
504 		LOG_ERR("SLC Connection ERROR in response");
505 		hf_slc_error(hf_at);
506 		return -EINVAL;
507 	}
508 
509 	err = hfp_hf_send_cmd(hf, cind_status_resp, cind_status_finish,
510 			      "AT+CIND?");
511 	if (err < 0) {
512 		hf_slc_error(hf_at);
513 		return err;
514 	}
515 
516 	return 0;
517 }
518 
brsf_finish(struct at_client * hf_at,enum at_result result,enum at_cme cme_err)519 int brsf_finish(struct at_client *hf_at, enum at_result result,
520 		enum at_cme cme_err)
521 {
522 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
523 	int err;
524 
525 	if (result != AT_RESULT_OK) {
526 		LOG_ERR("SLC Connection ERROR in response");
527 		hf_slc_error(hf_at);
528 		return -EINVAL;
529 	}
530 
531 	err = hfp_hf_send_cmd(hf, cind_resp, cind_finish, "AT+CIND=?");
532 	if (err < 0) {
533 		hf_slc_error(hf_at);
534 		return err;
535 	}
536 
537 	return 0;
538 }
539 
hf_slc_establish(struct bt_hfp_hf * hf)540 int hf_slc_establish(struct bt_hfp_hf *hf)
541 {
542 	int err;
543 
544 	LOG_DBG("");
545 
546 	err = hfp_hf_send_cmd(hf, brsf_resp, brsf_finish, "AT+BRSF=%u",
547 			      hf->hf_features);
548 	if (err < 0) {
549 		hf_slc_error(&hf->at);
550 		return err;
551 	}
552 
553 	return 0;
554 }
555 
bt_hfp_hf_lookup_bt_conn(struct bt_conn * conn)556 static struct bt_hfp_hf *bt_hfp_hf_lookup_bt_conn(struct bt_conn *conn)
557 {
558 	int i;
559 
560 	for (i = 0; i < ARRAY_SIZE(bt_hfp_hf_pool); i++) {
561 		struct bt_hfp_hf *hf = &bt_hfp_hf_pool[i];
562 
563 		if (hf->rfcomm_dlc.session->br_chan.chan.conn == conn) {
564 			return hf;
565 		}
566 	}
567 
568 	return NULL;
569 }
570 
bt_hfp_hf_send_cmd(struct bt_conn * conn,enum bt_hfp_hf_at_cmd cmd)571 int bt_hfp_hf_send_cmd(struct bt_conn *conn, enum bt_hfp_hf_at_cmd cmd)
572 {
573 	struct bt_hfp_hf *hf;
574 	int err;
575 
576 	LOG_DBG("");
577 
578 	if (!conn) {
579 		LOG_ERR("Invalid connection");
580 		return -ENOTCONN;
581 	}
582 
583 	hf = bt_hfp_hf_lookup_bt_conn(conn);
584 	if (!hf) {
585 		LOG_ERR("No HF connection found");
586 		return -ENOTCONN;
587 	}
588 
589 	switch (cmd) {
590 	case BT_HFP_HF_ATA:
591 		err = hfp_hf_send_cmd(hf, NULL, cmd_complete, "ATA");
592 		if (err < 0) {
593 			LOG_ERR("Failed ATA");
594 			return err;
595 		}
596 		break;
597 	case BT_HFP_HF_AT_CHUP:
598 		err = hfp_hf_send_cmd(hf, NULL, cmd_complete, "AT+CHUP");
599 		if (err < 0) {
600 			LOG_ERR("Failed AT+CHUP");
601 			return err;
602 		}
603 		break;
604 	default:
605 		LOG_ERR("Invalid AT Command");
606 		return -EINVAL;
607 	}
608 
609 	return 0;
610 }
611 
hfp_hf_connected(struct bt_rfcomm_dlc * dlc)612 static void hfp_hf_connected(struct bt_rfcomm_dlc *dlc)
613 {
614 	struct bt_hfp_hf *hf = CONTAINER_OF(dlc, struct bt_hfp_hf, rfcomm_dlc);
615 
616 	LOG_DBG("hf connected");
617 
618 	BT_ASSERT(hf);
619 	hf_slc_establish(hf);
620 }
621 
hfp_hf_disconnected(struct bt_rfcomm_dlc * dlc)622 static void hfp_hf_disconnected(struct bt_rfcomm_dlc *dlc)
623 {
624 	struct bt_conn *conn = dlc->session->br_chan.chan.conn;
625 
626 	LOG_DBG("hf disconnected!");
627 	if (bt_hf->disconnected) {
628 		bt_hf->disconnected(conn);
629 	}
630 }
631 
hfp_hf_recv(struct bt_rfcomm_dlc * dlc,struct net_buf * buf)632 static void hfp_hf_recv(struct bt_rfcomm_dlc *dlc, struct net_buf *buf)
633 {
634 	struct bt_hfp_hf *hf = CONTAINER_OF(dlc, struct bt_hfp_hf, rfcomm_dlc);
635 
636 	if (at_parse_input(&hf->at, buf) < 0) {
637 		LOG_ERR("Parsing failed");
638 	}
639 }
640 
bt_hfp_hf_accept(struct bt_conn * conn,struct bt_rfcomm_dlc ** dlc)641 static int bt_hfp_hf_accept(struct bt_conn *conn, struct bt_rfcomm_dlc **dlc)
642 {
643 	int i;
644 	static struct bt_rfcomm_dlc_ops ops = {
645 		.connected = hfp_hf_connected,
646 		.disconnected = hfp_hf_disconnected,
647 		.recv = hfp_hf_recv,
648 	};
649 
650 	LOG_DBG("conn %p", conn);
651 
652 	for (i = 0; i < ARRAY_SIZE(bt_hfp_hf_pool); i++) {
653 		struct bt_hfp_hf *hf = &bt_hfp_hf_pool[i];
654 		int j;
655 
656 		if (hf->rfcomm_dlc.session) {
657 			continue;
658 		}
659 
660 		hf->at.buf = hf->hf_buffer;
661 		hf->at.buf_max_len = HF_MAX_BUF_LEN;
662 
663 		hf->rfcomm_dlc.ops = &ops;
664 		hf->rfcomm_dlc.mtu = BT_HFP_MAX_MTU;
665 
666 		*dlc = &hf->rfcomm_dlc;
667 
668 		/* Set the supported features*/
669 		hf->hf_features = BT_HFP_HF_SUPPORTED_FEATURES;
670 
671 		for (j = 0; j < HF_MAX_AG_INDICATORS; j++) {
672 			hf->ind_table[j] = -1;
673 		}
674 
675 		return 0;
676 	}
677 
678 	LOG_ERR("Unable to establish HF connection (%p)", conn);
679 
680 	return -ENOMEM;
681 }
682 
hfp_hf_init(void)683 static void hfp_hf_init(void)
684 {
685 	static struct bt_rfcomm_server chan = {
686 		.channel = BT_RFCOMM_CHAN_HFP_HF,
687 		.accept = bt_hfp_hf_accept,
688 	};
689 
690 	bt_rfcomm_server_register(&chan);
691 }
692 
bt_hfp_hf_register(struct bt_hfp_hf_cb * cb)693 int bt_hfp_hf_register(struct bt_hfp_hf_cb *cb)
694 {
695 	if (!cb) {
696 		return -EINVAL;
697 	}
698 
699 	if (bt_hf) {
700 		return -EALREADY;
701 	}
702 
703 	bt_hf = cb;
704 
705 	hfp_hf_init();
706 
707 	return 0;
708 }
709