3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2014 Intel Corporation. All rights reserved.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include <sys/socket.h>
31 #include "src/shared/hfp.h"
32 #include "src/shared/tester.h"
39 struct hfp_hf *hfp_hf;
40 const struct test_data *data;
41 unsigned int pdu_offset;
48 enum hfp_gw_cmd_type type;
54 struct test_pdu *pdu_list;
55 hfp_result_func_t result_func;
56 hfp_response_func_t response_func;
57 hfp_hf_result_func_t hf_result_func;
61 #define data(args...) ((const unsigned char[]) { args })
63 #define raw_pdu(args...) \
67 .size = sizeof(data(args)), \
75 #define type_pdu(cmd_type, args...) \
79 .size = sizeof(data(args)), \
83 #define frg_pdu(args...) \
87 .size = sizeof(data(args)), \
91 #define define_test(name, function, result_function, args...) \
93 const struct test_pdu pdus[] = { \
96 static struct test_data data; \
97 data.test_name = g_strdup(name); \
98 data.pdu_list = g_memdup(pdus, sizeof(pdus)); \
99 data.result_func = result_function; \
100 tester_add(name, &data, NULL, function, NULL); \
101 data.test_handler = test_handler; \
104 #define define_hf_test(name, function, result_func, response_function, \
107 const struct test_pdu pdus[] = { \
110 static struct test_data data; \
111 data.test_name = g_strdup(name); \
112 data.pdu_list = g_memdup(pdus, sizeof(pdus)); \
113 data.hf_result_func = result_func; \
114 data.response_func = response_function; \
115 tester_add(name, &data, NULL, function, NULL); \
116 data.test_handler = test_hf_handler; \
119 static void test_free(gconstpointer user_data)
121 const struct test_data *data = user_data;
123 g_free(data->test_name);
124 g_free(data->pdu_list);
127 static void destroy_context(struct context *context)
129 if (context->watch_id)
130 g_source_remove(context->watch_id);
132 test_free(context->data);
135 hfp_gw_unref(context->hfp);
138 hfp_hf_unref(context->hfp_hf);
143 static gboolean context_quit(gpointer user_data)
145 struct context *context = user_data;
150 destroy_context(context);
151 tester_test_passed();
155 static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
158 struct context *context = user_data;
159 const struct test_pdu *pdu;
161 pdu = &context->data->pdu_list[context->pdu_offset++];
163 g_assert(!pdu->valid);
164 context->watch_id = 0;
166 context_quit(context);
171 static gboolean send_pdu(gpointer user_data)
173 struct context *context = user_data;
174 const struct test_pdu *pdu;
177 pdu = &context->data->pdu_list[context->pdu_offset++];
178 if (!pdu || !pdu->valid)
181 len = write(context->fd_server, pdu->data, pdu->size);
182 g_assert_cmpint(len, ==, pdu->size);
184 pdu = &context->data->pdu_list[context->pdu_offset];
186 g_idle_add(send_pdu, context);
191 static gboolean test_hf_handler(GIOChannel *channel, GIOCondition cond,
194 struct context *context = user_data;
197 GError *error = NULL;
199 if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
203 g_io_channel_read_chars(channel, buf, 60, &bytes_read, &error);
210 context->watch_id = 0;
212 context_quit(context);
217 static void cmd_handler(const char *command, void *user_data)
219 struct context *context = user_data;
220 const struct test_pdu *pdu;
221 unsigned int cmd_len = strlen(command);
223 pdu = &context->data->pdu_list[context->pdu_offset++];
225 g_assert(cmd_len == pdu->size);
226 g_assert(!memcmp(command, pdu->data, cmd_len));
228 hfp_gw_send_result(context->hfp, HFP_RESULT_ERROR);
231 static void prefix_handler(struct hfp_context *result,
232 enum hfp_gw_cmd_type type, void *user_data)
234 struct context *context = user_data;
235 const struct test_pdu *pdu;
237 pdu = &context->data->pdu_list[context->pdu_offset++];
239 g_assert(type == pdu->type);
241 hfp_gw_send_result(context->hfp, HFP_RESULT_ERROR);
244 static struct context *create_context(gconstpointer data)
246 struct context *context = g_new0(struct context, 1);
249 const struct test_data *d = data;
251 err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
254 channel = g_io_channel_unix_new(sv[1]);
256 g_io_channel_set_close_on_unref(channel, TRUE);
257 g_io_channel_set_encoding(channel, NULL, NULL);
258 g_io_channel_set_buffered(channel, FALSE);
260 context->watch_id = g_io_add_watch(channel,
261 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
262 d->test_handler, context);
264 g_assert(context->watch_id > 0);
266 g_io_channel_unref(channel);
268 context->fd_server = sv[1];
269 context->fd_client = sv[0];
270 context->data = data;
275 static void test_init(gconstpointer data)
277 struct context *context = create_context(data);
279 context->hfp = hfp_gw_new(context->fd_client);
281 g_assert(context->hfp);
282 g_assert(hfp_gw_set_close_on_unref(context->hfp, true));
284 hfp_gw_unref(context->hfp);
287 context_quit(context);
290 static void test_command_handler(gconstpointer data)
292 struct context *context = create_context(data);
293 const struct test_pdu *pdu;
297 context->hfp = hfp_gw_new(context->fd_client);
298 g_assert(context->hfp);
300 pdu = &context->data->pdu_list[context->pdu_offset++];
302 ret = hfp_gw_set_close_on_unref(context->hfp, true);
305 ret = hfp_gw_set_command_handler(context->hfp, cmd_handler,
309 len = write(context->fd_server, pdu->data, pdu->size);
310 g_assert_cmpint(len, ==, pdu->size);
312 context_quit(context);
315 static void test_register(gconstpointer data)
317 struct context *context = create_context(data);
318 const struct test_pdu *pdu;
322 context->hfp = hfp_gw_new(context->fd_client);
323 g_assert(context->hfp);
325 pdu = &context->data->pdu_list[context->pdu_offset++];
327 ret = hfp_gw_set_close_on_unref(context->hfp, true);
330 if (context->data->result_func) {
331 ret = hfp_gw_register(context->hfp, context->data->result_func,
332 (char *)pdu->data, context, NULL);
336 pdu = &context->data->pdu_list[context->pdu_offset++];
338 len = write(context->fd_server, pdu->data, pdu->size);
339 g_assert_cmpint(len, ==, pdu->size);
341 context_quit(context);
344 static void test_fragmented(gconstpointer data)
346 struct context *context = create_context(data);
349 context->hfp = hfp_gw_new(context->fd_client);
350 g_assert(context->hfp);
352 ret = hfp_gw_set_close_on_unref(context->hfp, true);
355 g_idle_add(send_pdu, context);
358 static void test_send_and_close(gconstpointer data)
360 struct context *context = create_context(data);
363 context->hfp = hfp_gw_new(context->fd_client);
364 g_assert(context->hfp);
366 ret = hfp_gw_set_close_on_unref(context->hfp, true);
371 hfp_gw_unref(context->hfp);
374 context_quit(context);
377 static void check_ustring_1(struct hfp_context *result,
378 enum hfp_gw_cmd_type type, void *user_data)
380 struct context *context = user_data;
381 const struct test_pdu *pdu;
382 unsigned int i = 3, j = 0;
385 pdu = &context->data->pdu_list[context->pdu_offset++];
387 g_assert(type == pdu->type);
389 g_assert(hfp_context_get_unquoted_string(result, str, sizeof(str)));
391 while (context->data->pdu_list[1].data[i] != '\r') {
392 g_assert(j < sizeof(str));
393 g_assert(str[j] == context->data->pdu_list[1].data[i]);
399 g_assert(str[j] == '\0');
401 hfp_gw_send_result(context->hfp, HFP_RESULT_ERROR);
404 static void check_ustring_2(struct hfp_context *result,
405 enum hfp_gw_cmd_type type, void *user_data)
407 struct context *context = user_data;
408 const struct test_pdu *pdu;
411 memset(str, 'X', sizeof(str));
413 pdu = &context->data->pdu_list[context->pdu_offset++];
415 g_assert(type == pdu->type);
417 g_assert(!hfp_context_get_unquoted_string(result, str, 3));
419 g_assert(str[3] == 'X');
421 hfp_gw_send_result(context->hfp, HFP_RESULT_ERROR);
424 static void check_string_1(struct hfp_context *result,
425 enum hfp_gw_cmd_type type, void *user_data)
427 struct context *context = user_data;
428 const struct test_pdu *pdu;
429 unsigned int i = 4, j = 0;
432 pdu = &context->data->pdu_list[context->pdu_offset++];
434 g_assert(type == pdu->type);
436 g_assert(hfp_context_get_string(result, str, sizeof(str)));
438 while (context->data->pdu_list[1].data[i] != '\"') {
439 g_assert(j < sizeof(str));
440 g_assert(str[j] == context->data->pdu_list[1].data[i]);
446 g_assert(context->data->pdu_list[1].data[i] == '\"');
447 g_assert(str[j] == '\0');
449 hfp_gw_send_result(context->hfp, HFP_RESULT_ERROR);
452 static void check_string_2(struct hfp_context *result,
453 enum hfp_gw_cmd_type type, void *user_data)
455 struct context *context = user_data;
456 const struct test_pdu *pdu;
459 memset(str, 'X', sizeof(str));
461 pdu = &context->data->pdu_list[context->pdu_offset++];
463 g_assert(type == pdu->type);
465 g_assert(!hfp_context_get_string(result, str, 3));
467 g_assert(str[3] == 'X');
469 hfp_gw_send_result(context->hfp, HFP_RESULT_ERROR);
472 static void check_string_3(struct hfp_context *result,
473 enum hfp_gw_cmd_type type, void *user_data)
475 struct context *context = user_data;
476 const struct test_pdu *pdu;
478 pdu = &context->data->pdu_list[context->pdu_offset++];
480 g_assert(type == pdu->type);
482 hfp_gw_send_result(context->hfp, HFP_RESULT_ERROR);
485 static void test_hf_init(gconstpointer data)
487 struct context *context = create_context(data);
489 context->hfp_hf = hfp_hf_new(context->fd_client);
490 g_assert(context->hfp_hf);
491 g_assert(hfp_hf_set_close_on_unref(context->hfp_hf, true));
493 hfp_hf_unref(context->hfp_hf);
494 context->hfp_hf = NULL;
496 context_quit(context);
499 static bool unsolicited_resp = false;
501 static void hf_unsolicited_resp_cb(struct hfp_context *context,
503 unsolicited_resp = true;
506 static void hf_response_with_data(enum hfp_result res,
507 enum hfp_error cme_err,
510 struct context *context = user_data;
512 g_assert(unsolicited_resp);
513 unsolicited_resp = false;
515 hfp_hf_disconnect(context->hfp_hf);
518 static void hf_cme_error_response_cb(enum hfp_result res,
519 enum hfp_error cme_err,
522 struct context *context = user_data;
524 g_assert_cmpint(res, ==, HFP_RESULT_CME_ERROR);
525 g_assert_cmpint(cme_err, ==, 30);
527 hfp_hf_disconnect(context->hfp_hf);
530 static void hf_response_cb(enum hfp_result res, enum hfp_error cme_err,
533 struct context *context = user_data;
535 hfp_hf_disconnect(context->hfp_hf);
538 static void test_hf_send_command(gconstpointer data)
540 struct context *context = create_context(data);
541 const struct test_pdu *pdu;
544 context->hfp_hf = hfp_hf_new(context->fd_client);
545 g_assert(context->hfp_hf);
547 ret = hfp_hf_set_close_on_unref(context->hfp_hf, true);
550 if (context->data->response_func) {
551 if (context->data->hf_result_func) {
552 pdu = &context->data->pdu_list[context->pdu_offset++];
554 ret = hfp_hf_register(context->hfp_hf,
555 context->data->hf_result_func,
561 pdu = &context->data->pdu_list[context->pdu_offset++];
563 ret = hfp_hf_send_command(context->hfp_hf,
564 context->data->response_func,
565 context, (char *)pdu->data);
569 context_quit(context);
571 static void hf_chld_result_handler(struct hfp_context *hf_context,
574 struct context *context = user_data;
577 g_assert(hf_context);
578 g_assert(hfp_context_get_unquoted_string(hf_context, str,
580 g_assert_cmpstr(str, ==, "1");
581 g_assert(hfp_context_get_unquoted_string(hf_context, str,
583 g_assert_cmpstr(str, ==, "2x");
585 hfp_hf_disconnect(context->hfp_hf);
588 static void hf_chld_skip_field(struct hfp_context *hf_context,
591 struct context *context = user_data;
594 g_assert(hf_context);
596 hfp_context_skip_field(hf_context);
598 g_assert(hfp_context_get_unquoted_string(hf_context, str,
600 g_assert_cmpstr(str, ==, "2x");
602 hfp_hf_disconnect(context->hfp_hf);
605 static void hf_clcc_result_handler(struct hfp_context *hf_context,
608 struct context *context = user_data;
612 g_assert(hf_context);
613 g_assert(hfp_context_open_container(hf_context));
614 g_assert(hfp_context_get_string(hf_context, name, sizeof(name)));
615 g_assert_cmpstr(name, ==, "call");
616 g_assert(hfp_context_open_container(hf_context));
617 g_assert(hfp_context_get_number(hf_context, &val1));
618 g_assert_cmpint(val1, ==, 0);
619 g_assert(hfp_context_get_number(hf_context, &val1));
620 g_assert_cmpint(val1, ==, 1);
621 g_assert(hfp_context_close_container(hf_context));
622 g_assert(hfp_context_close_container(hf_context));
624 g_assert(hfp_context_open_container(hf_context));
625 g_assert(hfp_context_get_string(hf_context, name, sizeof(name)));
626 g_assert_cmpstr(name, ==, "callsetup");
627 g_assert(hfp_context_open_container(hf_context));
628 g_assert(hfp_context_get_range(hf_context, &val1, &val2));
629 g_assert_cmpint(val1, ==, 0);
630 g_assert_cmpint(val2, ==, 3);
631 g_assert(hfp_context_close_container(hf_context));
632 g_assert(hfp_context_close_container(hf_context));
634 hfp_hf_disconnect(context->hfp_hf);
637 static void hf_result_handler(struct hfp_context *result,
640 struct context *context = user_data;
642 hfp_hf_disconnect(context->hfp_hf);
645 static void test_hf_unsolicited(gconstpointer data)
647 struct context *context = create_context(data);
650 context->hfp_hf = hfp_hf_new(context->fd_client);
651 g_assert(context->hfp_hf);
653 ret = hfp_hf_set_close_on_unref(context->hfp_hf, true);
656 if (context->data->hf_result_func) {
657 const struct test_pdu *pdu;
659 pdu = &context->data->pdu_list[context->pdu_offset++];
661 ret = hfp_hf_register(context->hfp_hf,
662 context->data->hf_result_func,
663 (char *)pdu->data, context,
671 static void test_hf_robustness(gconstpointer data)
673 struct context *context = create_context(data);
676 context->hfp_hf = hfp_hf_new(context->fd_client);
677 g_assert(context->hfp_hf);
679 ret = hfp_hf_set_close_on_unref(context->hfp_hf, true);
684 hfp_hf_unref(context->hfp_hf);
685 context->hfp_hf = NULL;
687 context_quit(context);
690 int main(int argc, char *argv[])
692 tester_init(&argc, &argv);
694 define_test("/hfp/test_init", test_init, NULL, data_end());
695 define_test("/hfp/test_cmd_handler_1", test_command_handler, NULL,
696 raw_pdu('A', 'T', '+', 'B', 'R', 'S', 'F', '\r'),
697 raw_pdu('A', 'T', '+', 'B', 'R', 'S', 'F'),
699 define_test("/hfp/test_cmd_handler_2", test_command_handler, NULL,
700 raw_pdu('A', 'T', 'D', '1', '2', '3', '4', '\r'),
701 raw_pdu('A', 'T', 'D', '1', '2', '3', '4'),
703 define_test("/hfp/test_register_1", test_register, prefix_handler,
704 raw_pdu('+', 'B', 'R', 'S', 'F', '\0'),
705 raw_pdu('A', 'T', '+', 'B', 'R', 'S', 'F', '\r'),
706 type_pdu(HFP_GW_CMD_TYPE_COMMAND, 0),
708 define_test("/hfp/test_register_2", test_register, prefix_handler,
709 raw_pdu('+', 'B', 'R', 'S', 'F', '\0'),
710 raw_pdu('A', 'T', '+', 'B', 'R', 'S', 'F', '=', '\r'),
711 type_pdu(HFP_GW_CMD_TYPE_SET, 0),
713 define_test("/hfp/test_register_3", test_register, prefix_handler,
714 raw_pdu('+', 'B', 'R', 'S', 'F', '\0'),
715 raw_pdu('A', 'T', '+', 'B', 'R', 'S', 'F', '?', '\r'),
716 type_pdu(HFP_GW_CMD_TYPE_READ, 0),
718 define_test("/hfp/test_register_4", test_register, prefix_handler,
719 raw_pdu('+', 'B', 'R', 'S', 'F', '\0'),
720 raw_pdu('A', 'T', '+', 'B', 'R', 'S', 'F', '=', '?',
722 type_pdu(HFP_GW_CMD_TYPE_TEST, 0),
724 define_test("/hfp/test_register_5", test_register, prefix_handler,
726 raw_pdu('A', 'T', 'D', '1', '2', '3', '4', '5', '\r'),
727 type_pdu(HFP_GW_CMD_TYPE_SET, 0),
729 define_test("/hfp/test_fragmented_1", test_fragmented, NULL,
730 frg_pdu('A'), frg_pdu('T'), frg_pdu('+'), frg_pdu('B'),
731 frg_pdu('R'), frg_pdu('S'), frg_pdu('F'), frg_pdu('\r'),
733 define_test("/hfp/test_ustring_1", test_register, check_ustring_1,
735 raw_pdu('A', 'T', 'D', '0', '1', '2', '3', '\r'),
736 type_pdu(HFP_GW_CMD_TYPE_SET, 0),
738 define_test("/hfp/test_ustring_2", test_register, check_ustring_2,
740 raw_pdu('A', 'T', 'D', '0', '1', '2', '3', '\r'),
741 type_pdu(HFP_GW_CMD_TYPE_SET, 0),
743 define_test("/hfp/test_string_1", test_register, check_string_1,
745 raw_pdu('A', 'T', 'D', '\"', '0', '1', '2', '3', '\"',
747 type_pdu(HFP_GW_CMD_TYPE_SET, 0),
749 define_test("/hfp/test_string_2", test_register, check_string_2,
751 raw_pdu('A', 'T', 'D', '\"', '0', '1', '2', '3', '\"',
753 type_pdu(HFP_GW_CMD_TYPE_SET, 0),
755 define_test("/hfp/test_corrupted_1", test_register, check_string_3,
757 raw_pdu('\r', 'A', 'T', 'D', '\"', '0', '1', '2', '3',
759 type_pdu(HFP_GW_CMD_TYPE_SET, 0),
761 define_test("/hfp/test_empty", test_send_and_close, NULL,
764 define_hf_test("/hfp_hf/test_init", test_hf_init, NULL, NULL,
766 define_hf_test("/hfp_hf/test_send_command_1", test_hf_send_command,
767 NULL, hf_response_cb,
768 raw_pdu('A', 'T', '+', 'B', 'R', 'S', 'F', '\0'),
769 raw_pdu('\r', '\n', 'O', 'k', '\r', '\n'),
772 define_hf_test("/hfp_hf/test_send_command_2", test_hf_send_command,
773 hf_unsolicited_resp_cb,
774 hf_response_with_data,
775 raw_pdu('+', 'B', 'R', 'S', 'F', '\0'),
776 raw_pdu('A', 'T', '+', 'B', 'R', 'S', 'F', '\0'),
777 frg_pdu('\r', '\n', '+', 'B', 'R', 'S', 'F', '\r',
779 frg_pdu('\r', '\n', 'O', 'k', '\r', '\n'),
782 define_hf_test("/hfp_hf/test_send_command_3", test_hf_send_command,
783 NULL, hf_cme_error_response_cb,
784 raw_pdu('A', 'T', '+', 'C', 'H', 'L', 'D', '=',
786 frg_pdu('\r', '\n', '+', 'C', 'M', 'E', ' ', 'E'),
787 frg_pdu('R', 'R', 'O', 'R', ':', '3', '0', '\r', '\n'),
790 define_hf_test("/hfp_hf/test_unsolicited_1", test_hf_unsolicited,
791 hf_result_handler, NULL,
792 raw_pdu('+', 'C', 'L', 'C', 'C', '\0'),
793 frg_pdu('\r', '\n', '+', 'C', 'L', 'C'),
794 frg_pdu('C', '\r', '\n'),
797 define_hf_test("/hfp_hf/test_unsolicited_2", test_hf_unsolicited,
798 hf_result_handler, NULL,
799 raw_pdu('+', 'C', 'L', 'C', 'C', '\0'),
800 frg_pdu('\r', '\n', '+', 'C', 'L', 'C', 'C', ':', '1'),
801 frg_pdu(',', '3', ',', '0', '\r', '\n'),
804 define_hf_test("/hfp_hf/test_unsolicited_3", test_hf_unsolicited,
805 hf_result_handler, NULL,
806 raw_pdu('+', 'C', 'L', 'C', 'C', '\0'),
807 frg_pdu('\r'), frg_pdu('\n'), frg_pdu('+'),
808 frg_pdu('C'), frg_pdu('L'), frg_pdu('C'), frg_pdu('C'),
809 frg_pdu(':'), frg_pdu('1'), frg_pdu(','), frg_pdu('3'),
810 frg_pdu(','), frg_pdu('0'), frg_pdu('\r'),
814 define_hf_test("/hfp_hf/test_corrupted_1", test_hf_unsolicited,
815 hf_result_handler, NULL,
816 raw_pdu('+', 'C', 'L', 'C', 'C', '\0'),
817 frg_pdu('\r', 'X', '\r', '\n'),
818 frg_pdu('+', 'C', 'L', 'C', 'C', ':', '1', ',', '3'),
819 frg_pdu(',', '0', '\r', '\n'),
822 define_hf_test("/hfp_hf/test_corrupted_2", test_hf_unsolicited,
823 hf_result_handler, NULL,
824 raw_pdu('+', 'C', 'L', 'C', 'C', '\0'),
825 raw_pdu('+', 'C', 'L', 'C', 'C', '\r', '\n'),
828 define_hf_test("/hfp_hf/test_empty", test_hf_robustness, NULL, NULL,
829 raw_pdu('\r'), data_end());
831 define_hf_test("/hfp_hf/test_unknown", test_hf_robustness, NULL, NULL,
832 raw_pdu('\r', '\n', 'B', 'R', '\r', '\n'),
835 define_hf_test("/hfp_hf/test_context_parser_1", test_hf_unsolicited,
836 hf_clcc_result_handler, NULL,
837 raw_pdu('+', 'C', 'L', 'C', 'C', '\0'),
838 frg_pdu('+', 'C', 'L', 'C', 'C', ':'),
839 frg_pdu('(', '\"', 'c', 'a', 'l', 'l', '\"'),
840 frg_pdu('(', '0', ',', '1', ')', ')', ','),
841 frg_pdu('(', '\"', 'c', 'a', 'l', 'l', 's', 'e', 't'),
842 frg_pdu('u', 'p', '\"', ',', '(', '0', '-', '3', ')'),
843 frg_pdu(')', '\r', '\n'),
846 define_hf_test("/hfp_hf/test_context_parser_2", test_hf_unsolicited,
847 hf_chld_result_handler, NULL,
848 raw_pdu('+', 'C', 'H', 'L', 'D', '\0'),
849 frg_pdu('+', 'C', 'H', 'L', 'D', ':'),
850 frg_pdu('1', ',', '2', 'x', '\r', '\n'),
853 define_hf_test("/hfp_hf/test_context_skip_field", test_hf_unsolicited,
854 hf_chld_skip_field, NULL,
855 raw_pdu('+', 'C', 'H', 'L', 'D', '\0'),
856 frg_pdu('+', 'C', 'H', 'L', 'D', ':'),
857 frg_pdu('1', ',', '2', 'x', '\r', '\n'),