3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2000-2002 Maxim Krasnyansky <maxk@qualcomm.com>
6 * Copyright (C) 2003-2011 Marcel Holtmann <marcel@holtmann.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
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 General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
47 #define HANDLE_TABLE_SIZE 10
49 static handle_info handle_table[HANDLE_TABLE_SIZE];
59 #define CID_TABLE_SIZE 20
61 static cid_info cid_table[2][CID_TABLE_SIZE];
63 #define SCID cid_table[0]
64 #define DCID cid_table[1]
66 /* Can we move this to l2cap.h? */
72 static struct features l2cap_features[] = {
73 { "Flow control mode", L2CAP_FEAT_FLOWCTL },
74 { "Retransmission mode", L2CAP_FEAT_RETRANS },
75 { "Bi-directional QoS", L2CAP_FEAT_BIDIR_QOS },
76 { "Enhanced Retransmission mode", L2CAP_FEAT_ERTM },
77 { "Streaming mode", L2CAP_FEAT_STREAMING },
78 { "FCS Option", L2CAP_FEAT_FCS },
79 { "Extended Flow Specification", L2CAP_FEAT_EXT_FLOW },
80 { "Fixed Channels", L2CAP_FEAT_FIXED_CHAN },
81 { "Extended Window Size", L2CAP_FEAT_EXT_WINDOW },
82 { "Unicast Connectless Data Reception", L2CAP_FEAT_UCD },
86 static struct features l2cap_fix_chan[] = {
87 { "L2CAP Signalling Channel", L2CAP_FC_L2CAP },
88 { "L2CAP Connless", L2CAP_FC_CONNLESS },
89 { "AMP Manager Protocol", L2CAP_FC_A2MP },
93 static struct frame *add_handle(uint16_t handle)
95 register handle_info *t = handle_table;
98 for (i = 0; i < HANDLE_TABLE_SIZE; i++)
100 t[i].handle = handle;
106 static struct frame *get_frame(uint16_t handle)
108 register handle_info *t = handle_table;
111 for (i = 0; i < HANDLE_TABLE_SIZE; i++)
112 if (t[i].handle == handle)
115 return add_handle(handle);
118 static void add_cid(int in, uint16_t handle, uint16_t cid, uint16_t psm)
120 register cid_info *table = cid_table[in];
121 register int i, pos = -1;
124 for (i = 0; i < CID_TABLE_SIZE; i++) {
125 if ((pos < 0 && !table[i].cid) || table[i].cid == cid)
127 if (table[i].psm == psm)
132 table[pos].handle = handle;
133 table[pos].cid = cid;
134 table[pos].psm = psm;
135 table[pos].num = num;
140 static void del_cid(int in, uint16_t dcid, uint16_t scid)
153 for (t = 0; t < 2; t++) {
154 for (i = 0; i < CID_TABLE_SIZE; i++)
155 if (cid_table[t][i].cid == cid[t]) {
156 cid_table[t][i].handle = 0;
157 cid_table[t][i].cid = 0;
158 cid_table[t][i].psm = 0;
159 cid_table[t][i].num = 0;
160 cid_table[t][i].mode = 0;
166 static void del_handle(uint16_t handle)
170 for (t = 0; t < 2; t++) {
171 for (i = 0; i < CID_TABLE_SIZE; i++)
172 if (cid_table[t][i].handle == handle) {
173 cid_table[t][i].handle = 0;
174 cid_table[t][i].cid = 0;
175 cid_table[t][i].psm = 0;
176 cid_table[t][i].num = 0;
177 cid_table[t][i].mode = 0;
182 static uint16_t get_psm(int in, uint16_t handle, uint16_t cid)
184 register cid_info *table = cid_table[in];
187 for (i = 0; i < CID_TABLE_SIZE; i++)
188 if (table[i].handle == handle && table[i].cid == cid)
190 return parser.defpsm;
193 static uint16_t get_num(int in, uint16_t handle, uint16_t cid)
195 register cid_info *table = cid_table[in];
198 for (i = 0; i < CID_TABLE_SIZE; i++)
199 if (table[i].handle == handle && table[i].cid == cid)
204 static void set_mode(int in, uint16_t handle, uint16_t cid, uint8_t mode)
206 register cid_info *table = cid_table[in];
209 for (i = 0; i < CID_TABLE_SIZE; i++)
210 if (table[i].handle == handle && table[i].cid == cid)
211 table[i].mode = mode;
214 static uint8_t get_mode(int in, uint16_t handle, uint16_t cid)
216 register cid_info *table = cid_table[in];
219 for (i = 0; i < CID_TABLE_SIZE; i++)
220 if (table[i].handle == handle && table[i].cid == cid)
221 return table[i].mode;
225 static void set_ext_ctrl(int in, uint16_t handle, uint16_t cid,
228 register cid_info *table = cid_table[in];
231 for (i = 0; i < CID_TABLE_SIZE; i++)
232 if (table[i].handle == handle && table[i].cid == cid)
233 table[i].ext_ctrl = ext_ctrl;
236 static uint8_t get_ext_ctrl(int in, uint16_t handle, uint16_t cid)
238 register cid_info *table = cid_table[in];
241 for (i = 0; i < CID_TABLE_SIZE; i++)
242 if (table[i].handle == handle && table[i].cid == cid)
243 return table[i].ext_ctrl;
247 static uint32_t get_val(uint8_t *ptr, uint8_t len)
253 return get_le16(ptr);
255 return get_le32(ptr);
260 static char *reason2str(uint16_t reason)
264 return "Command not understood";
266 return "Signalling MTU exceeded";
268 return "Invalid CID in request";
274 static char *a2mpreason2str(uint16_t reason)
277 case A2MP_COMMAND_NOT_RECOGNIZED:
278 return "Command not recognized";
284 static char *connresult2str(uint16_t result)
288 return "Connection successful";
290 return "Connection pending";
292 return "Connection refused - PSM not supported";
294 return "Connection refused - security block";
296 return "Connection refused - no resources available";
302 static char *status2str(uint16_t status)
306 return "No futher information available";
308 return "Authentication pending";
310 return "Authorization pending";
316 static char *confresult2str(uint16_t result)
319 case L2CAP_CONF_SUCCESS:
321 case L2CAP_CONF_UNACCEPT:
322 return "Failure - unacceptable parameters";
323 case L2CAP_CONF_REJECT:
324 return "Failure - rejected (no reason provided)";
325 case L2CAP_CONF_UNKNOWN:
326 return "Failure - unknown options";
327 case L2CAP_CONF_PENDING:
329 case L2CAP_CONF_EFS_REJECT:
330 return "Failure - flowspec reject";
335 static char *inforesult2str(uint16_t result)
341 return "Not supported";
347 static char *type2str(uint8_t type)
350 case L2CAP_SERVTYPE_NOTRAFFIC:
352 case L2CAP_SERVTYPE_BESTEFFORT:
353 return "Best Effort";
354 case L2CAP_SERVTYPE_GUARANTEED:
361 static char *mode2str(uint8_t mode)
367 return "Retransmission";
369 return "Flow control";
371 return "Enhanced Retransmission";
379 static char *fcs2str(uint8_t fcs)
385 return "CRC16 Check";
391 static char *sar2str(uint8_t sar)
394 case L2CAP_SAR_UNSEGMENTED:
395 return "Unsegmented";
396 case L2CAP_SAR_START:
400 case L2CAP_SAR_CONTINUE:
401 return "Continuation";
408 static char *supervisory2str(uint8_t supervisory)
410 switch (supervisory) {
412 return "Receiver Ready (RR)";
413 case L2CAP_SUPER_REJ:
414 return "Reject (REJ)";
415 case L2CAP_SUPER_RNR:
416 return "Receiver Not Ready (RNR)";
417 case L2CAP_SUPER_SREJ:
418 return "Select Reject (SREJ)";
420 return "Bad Supervisory";
424 static char *ampctrltype2str(uint8_t type)
436 static char *ampctrlstatus2str(uint8_t status)
439 case AMP_CTRL_POWERED_DOWN:
440 return "Powered down";
441 case AMP_CTRL_BLUETOOTH_ONLY:
442 return "Bluetooth only";
443 case AMP_CTRL_NO_CAPACITY:
444 return "No capacity";
445 case AMP_CTRL_LOW_CAPACITY:
446 return "Low capacity";
447 case AMP_CTRL_MEDIUM_CAPACITY:
448 return "Medium capacity";
449 case AMP_CTRL_HIGH_CAPACITY:
450 return "High capacity";
451 case AMP_CTRL_FULL_CAPACITY:
452 return "Full capacity";
459 static char *a2mpstatus2str(uint8_t status)
462 case A2MP_STATUS_SUCCESS:
464 case A2MP_STATUS_INVALID_CTRL_ID:
465 return "Invalid Controller ID";
471 static char *a2mpcplstatus2str(uint8_t status)
474 case A2MP_STATUS_SUCCESS:
476 case A2MP_STATUS_INVALID_CTRL_ID:
477 return "Invalid Controller ID";
478 case A2MP_STATUS_UNABLE_START_LINK_CREATION:
479 return "Failed - Unable to start link creation";
480 case A2MP_STATUS_COLLISION_OCCURED:
481 return "Failed - Collision occured";
482 case A2MP_STATUS_DISCONN_REQ_RECVD:
483 return "Failed - Disconnect physical link received";
484 case A2MP_STATUS_PHYS_LINK_EXISTS:
485 return "Failed - Physical link already exists";
486 case A2MP_STATUS_SECURITY_VIOLATION:
487 return "Failed - Security violation";
493 static char *a2mpdplstatus2str(uint8_t status)
496 case A2MP_STATUS_SUCCESS:
498 case A2MP_STATUS_INVALID_CTRL_ID:
499 return "Invalid Controller ID";
500 case A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS:
501 return "Failed - No Physical Link exists";
507 static inline void command_rej(int level, struct frame *frm)
509 l2cap_cmd_rej *h = frm->ptr;
510 uint16_t reason = btohs(h->reason);
513 printf("Command rej: reason %d", reason);
517 printf(" mtu %d\n", get_val(frm->ptr + L2CAP_CMD_REJ_SIZE, 2));
520 cid = get_val(frm->ptr + L2CAP_CMD_REJ_SIZE, 4);
521 printf(" dcid 0x%4.4x scid 0x%4.4x\n", cid & 0xffff, cid >> 16);
528 p_indent(level + 1, frm);
529 printf("%s\n", reason2str(reason));
532 static inline void conn_req(int level, struct frame *frm)
534 l2cap_conn_req *h = frm->ptr;
535 uint16_t psm = btohs(h->psm);
536 uint16_t scid = btohs(h->scid);
538 add_cid(frm->in, frm->handle, scid, psm);
540 if (p_filter(FILT_L2CAP))
543 printf("Connect req: psm %d scid 0x%4.4x\n", psm, scid);
546 static inline void conn_rsp(int level, struct frame *frm)
548 l2cap_conn_rsp *h = frm->ptr;
549 uint16_t scid = btohs(h->scid);
550 uint16_t dcid = btohs(h->dcid);
551 uint16_t result = btohs(h->result);
552 uint16_t status = btohs(h->status);
556 case L2CAP_CR_SUCCESS:
557 if ((psm = get_psm(!frm->in, frm->handle, scid)))
558 add_cid(frm->in, frm->handle, dcid, psm);
565 del_cid(frm->in, dcid, scid);
569 if (p_filter(FILT_L2CAP))
572 printf("Connect rsp: dcid 0x%4.4x scid 0x%4.4x result %d status %d\n",
573 dcid, scid, result, status);
575 p_indent(level + 1, frm);
576 printf("%s", connresult2str(result));
578 if (result == 0x0001)
579 printf(" - %s\n", status2str(status));
584 static void conf_rfc(void *ptr, int len, int in, uint16_t handle,
589 mode = *((uint8_t *) ptr);
590 set_mode(!in, handle, cid, mode);
592 printf("RFC 0x%02x (%s", mode, mode2str(mode));
593 if (mode >= 0x01 && mode <= 0x04) {
594 uint8_t txwin, maxtrans;
595 uint16_t rto, mto, mps;
596 txwin = *((uint8_t *) (ptr + 1));
597 maxtrans = *((uint8_t *) (ptr + 2));
598 rto = get_le16(ptr + 3);
599 mto = get_le16(ptr + 5);
600 mps = get_le16(ptr + 7);
601 printf(", TxWin %d, MaxTx %d, RTo %d, MTo %d, MPS %d",
602 txwin, maxtrans, rto, mto, mps);
607 static void conf_efs(void *ptr)
609 uint8_t id, ser_type;
611 uint32_t sdu_itime, access_lat, flush_to;
613 id = get_val(ptr, sizeof(id));
614 ser_type = get_val(ptr + 1, sizeof(ser_type));
615 max_sdu = get_val(ptr + 2, sizeof(max_sdu));
616 sdu_itime = get_val(ptr + 4, sizeof(sdu_itime));
617 access_lat = get_val(ptr + 8, sizeof(access_lat));
618 flush_to = get_val(ptr + 12, sizeof(flush_to));
620 printf("EFS (Id 0x%02x, SerType %s, MaxSDU 0x%04x, SDUitime 0x%08x, "
621 "AccLat 0x%08x, FlushTO 0x%08x)",
622 id, type2str(ser_type), max_sdu, sdu_itime,
623 access_lat, flush_to);
626 static void conf_fcs(void *ptr, int len)
630 fcs = *((uint8_t *) ptr);
631 printf("FCS Option");
633 printf(" 0x%2.2x (%s)", fcs, fcs2str(fcs));
636 static void conf_opt(int level, void *ptr, int len, int in, uint16_t handle,
642 l2cap_conf_opt *h = ptr;
644 ptr += L2CAP_CONF_OPT_SIZE + h->len;
645 len -= L2CAP_CONF_OPT_SIZE + h->len;
655 switch (h->type & 0x7f) {
657 set_mode(in, handle, cid, 0x00);
660 printf(" %d", get_val(h->val, h->len));
663 case L2CAP_CONF_FLUSH_TO:
666 printf(" %d", get_val(h->val, h->len));
672 printf(" 0x%02x (%s)", *(h->val + 1), type2str(*(h->val + 1)));
676 conf_rfc(h->val, h->len, in, handle, cid);
680 conf_fcs(h->val, h->len);
690 printf(" %d", get_val(h->val, h->len));
691 set_ext_ctrl(in, handle, cid, 1);
695 printf("Unknown (type %2.2x, len %d)", h->type & 0x7f, h->len);
707 static void conf_list(int level, uint8_t *list, int len)
712 for (i = 0; i < len; i++) {
713 switch (list[i] & 0x7f) {
717 case L2CAP_CONF_FLUSH_TO:
736 printf("%2.2x ", list[i] & 0x7f);
743 static inline void conf_req(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
745 l2cap_conf_req *h = frm->ptr;
746 uint16_t dcid = btohs(h->dcid);
747 int clen = btohs(cmd->len) - L2CAP_CONF_REQ_SIZE;
749 if (p_filter(FILT_L2CAP))
752 printf("Config req: dcid 0x%4.4x flags 0x%2.2x clen %d\n",
753 dcid, btohs(h->flags), clen);
756 conf_opt(level + 1, h->data, clen, frm->in, frm->handle,
760 static inline void conf_rsp(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
762 l2cap_conf_rsp *h = frm->ptr;
763 uint16_t scid = btohs(h->scid);
764 uint16_t result = btohs(h->result);
765 int clen = btohs(cmd->len) - L2CAP_CONF_RSP_SIZE;
767 if (p_filter(FILT_L2CAP))
770 printf("Config rsp: scid 0x%4.4x flags 0x%2.2x result %d clen %d\n",
771 scid, btohs(h->flags), result, clen);
775 p_indent(level + 1, frm);
776 printf("%s\n", confresult2str(result));
778 if (result == 0x0003)
779 conf_list(level + 1, h->data, clen);
781 conf_opt(level + 1, h->data, clen, frm->in,
784 p_indent(level + 1, frm);
785 printf("%s\n", confresult2str(result));
789 static inline void disconn_req(int level, struct frame *frm)
791 l2cap_disconn_req *h = frm->ptr;
793 if (p_filter(FILT_L2CAP))
796 printf("Disconn req: dcid 0x%4.4x scid 0x%4.4x\n",
797 btohs(h->dcid), btohs(h->scid));
800 static inline void disconn_rsp(int level, struct frame *frm)
802 l2cap_disconn_rsp *h = frm->ptr;
803 uint16_t dcid = btohs(h->dcid);
804 uint16_t scid = btohs(h->scid);
806 del_cid(frm->in, dcid, scid);
808 if (p_filter(FILT_L2CAP))
811 printf("Disconn rsp: dcid 0x%4.4x scid 0x%4.4x\n",
812 btohs(h->dcid), btohs(h->scid));
815 static inline void echo_req(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
817 if (p_filter(FILT_L2CAP))
820 printf("Echo req: dlen %d\n", btohs(cmd->len));
821 raw_dump(level, frm);
824 static inline void echo_rsp(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
826 if (p_filter(FILT_L2CAP))
829 printf("Echo rsp: dlen %d\n", btohs(cmd->len));
830 raw_dump(level, frm);
833 static void info_opt(int level, int type, void *ptr, int len)
843 printf("Connectionless MTU %d\n", get_val(ptr, len));
846 mask = get_val(ptr, len);
847 printf("Extended feature mask 0x%4.4x\n", mask);
848 if (parser.flags & DUMP_VERBOSE)
849 for (i=0; l2cap_features[i].name; i++)
850 if (mask & l2cap_features[i].flag) {
851 p_indent(level + 1, 0);
852 printf("%s\n", l2cap_features[i].name);
856 fc_mask = get_le64(ptr);
857 printf("Fixed channel list 0x%8.8" PRIx64 "\n", fc_mask);
858 if (parser.flags & DUMP_VERBOSE)
859 for (i=0; l2cap_fix_chan[i].name; i++)
860 if (fc_mask & l2cap_fix_chan[i].flag) {
861 p_indent(level + 1, 0);
862 printf("%s\n", l2cap_fix_chan[i].name);
866 printf("Unknown (len %d)\n", len);
871 static inline void info_req(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
873 l2cap_info_req *h = frm->ptr;
875 if (p_filter(FILT_L2CAP))
878 printf("Info req: type %d\n", btohs(h->type));
881 static inline void info_rsp(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
883 l2cap_info_rsp *h = frm->ptr;
884 uint16_t type = btohs(h->type);
885 uint16_t result = btohs(h->result);
886 int ilen = btohs(cmd->len) - L2CAP_INFO_RSP_SIZE;
888 if (p_filter(FILT_L2CAP))
891 printf("Info rsp: type %d result %d\n", type, result);
894 info_opt(level + 1, type, h->data, ilen);
896 p_indent(level + 1, frm);
897 printf("%s\n", inforesult2str(result));
901 static void l2cap_ctrl_ext_parse(int level, struct frame *frm, uint32_t ctrl)
903 p_indent(level, frm);
905 printf("%s:", ctrl & L2CAP_EXT_CTRL_FRAME_TYPE ? "S-frame" : "I-frame");
907 if (ctrl & L2CAP_EXT_CTRL_FRAME_TYPE) {
908 printf(" %s", supervisory2str((ctrl & L2CAP_EXT_CTRL_SUPERVISE_MASK) >>
909 L2CAP_EXT_CTRL_SUPER_SHIFT));
911 if (ctrl & L2CAP_EXT_CTRL_POLL)
914 uint8_t sar = (ctrl & L2CAP_EXT_CTRL_SAR_MASK) >>
915 L2CAP_EXT_CTRL_SAR_SHIFT;
916 printf(" %s", sar2str(sar));
917 if (sar == L2CAP_SAR_START) {
919 len = get_le16(frm->ptr);
920 frm->ptr += L2CAP_SDULEN_SIZE;
921 frm->len -= L2CAP_SDULEN_SIZE;
922 printf(" (len %d)", len);
924 printf(" TxSeq %d", (ctrl & L2CAP_EXT_CTRL_TXSEQ_MASK) >>
925 L2CAP_EXT_CTRL_TXSEQ_SHIFT);
928 printf(" ReqSeq %d", (ctrl & L2CAP_EXT_CTRL_REQSEQ_MASK) >>
929 L2CAP_EXT_CTRL_REQSEQ_SHIFT);
931 if (ctrl & L2CAP_EXT_CTRL_FINAL)
935 static void l2cap_ctrl_parse(int level, struct frame *frm, uint32_t ctrl)
937 p_indent(level, frm);
939 printf("%s:", ctrl & L2CAP_CTRL_FRAME_TYPE ? "S-frame" : "I-frame");
942 printf(" %s", supervisory2str((ctrl & L2CAP_CTRL_SUPERVISE_MASK) >>
943 L2CAP_CTRL_SUPER_SHIFT));
945 if (ctrl & L2CAP_CTRL_POLL)
948 uint8_t sar = (ctrl & L2CAP_CTRL_SAR_MASK) >> L2CAP_CTRL_SAR_SHIFT;
949 printf(" %s", sar2str(sar));
950 if (sar == L2CAP_SAR_START) {
952 len = get_le16(frm->ptr);
953 frm->ptr += L2CAP_SDULEN_SIZE;
954 frm->len -= L2CAP_SDULEN_SIZE;
955 printf(" (len %d)", len);
957 printf(" TxSeq %d", (ctrl & L2CAP_CTRL_TXSEQ_MASK) >> L2CAP_CTRL_TXSEQ_SHIFT);
960 printf(" ReqSeq %d", (ctrl & L2CAP_CTRL_REQSEQ_MASK) >> L2CAP_CTRL_REQSEQ_SHIFT);
962 if (ctrl & L2CAP_CTRL_FINAL)
966 static inline void create_req(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
968 l2cap_create_req *h = frm->ptr;
969 uint16_t psm = btohs(h->psm);
970 uint16_t scid = btohs(h->scid);
972 if (p_filter(FILT_L2CAP))
975 printf("Create chan req: psm 0x%4.4x scid 0x%4.4x ctrl id %d\n",
979 static inline void create_rsp(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
981 l2cap_create_rsp *h = frm->ptr;
982 uint16_t scid = btohs(h->scid);
983 uint16_t dcid = btohs(h->dcid);
984 uint16_t result = btohs(h->result);
985 uint16_t status = btohs(h->status);
987 if (p_filter(FILT_L2CAP))
990 printf("Create chan rsp: dcid 0x%4.4x scid 0x%4.4x result %d status %d\n",
991 dcid, scid, result, status);
994 static inline void move_req(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
996 l2cap_move_req *h = frm->ptr;
997 uint16_t icid = btohs(h->icid);
999 if (p_filter(FILT_L2CAP))
1002 printf("Move chan req: icid 0x%4.4x ctrl id %d\n", icid, h->id);
1005 static inline void move_rsp(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
1007 l2cap_move_rsp *h = frm->ptr;
1008 uint16_t icid = btohs(h->icid);
1009 uint16_t result = btohs(h->result);
1011 if (p_filter(FILT_L2CAP))
1014 printf("Move chan rsp: icid 0x%4.4x result %d\n", icid, result);
1017 static inline void move_cfm(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
1019 l2cap_move_cfm *h = frm->ptr;
1020 uint16_t icid = btohs(h->icid);
1021 uint16_t result = btohs(h->result);
1023 if (p_filter(FILT_L2CAP))
1026 printf("Move chan cfm: icid 0x%4.4x result %d\n", icid, result);
1029 static inline void move_cfm_rsp(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
1031 l2cap_move_cfm_rsp *h = frm->ptr;
1032 uint16_t icid = btohs(h->icid);
1034 if (p_filter(FILT_L2CAP))
1037 printf("Move chan cfm rsp: icid 0x%4.4x\n", icid);
1040 static inline void a2mp_command_rej(int level, struct frame *frm)
1042 struct a2mp_command_rej *h = frm->ptr;
1043 uint16_t reason = btohs(h->reason);
1045 printf("Command Reject: reason %d\n", reason);
1046 p_indent(level + 1, 0);
1047 printf("%s\n", a2mpreason2str(reason));
1050 static inline void a2mp_discover_req(int level, struct frame *frm, uint16_t len)
1052 struct a2mp_discover_req *h = frm->ptr;
1053 uint16_t mtu = btohs(h->mtu);
1054 uint8_t *octet = (uint8_t *)&(h->mask);
1058 printf("Discover req: mtu/mps %d ", mtu);
1065 mask = get_le16(octet);
1066 printf(" 0x%4.4x", mask);
1068 extension = octet[1] & 0x80;
1070 } while ((extension != 0) && (len >= 2));
1075 static inline void a2mp_ctrl_list_dump(int level, struct a2mp_ctrl *list, uint16_t len)
1078 printf("Controller list:\n");
1081 p_indent(level + 1, 0);
1082 printf("id %d type %d (%s) status 0x%2.2x (%s)\n",
1083 list->id, list->type, ampctrltype2str(list->type), list->status, ampctrlstatus2str(list->status));
1090 static inline void a2mp_discover_rsp(int level, struct frame *frm, uint16_t len)
1092 struct a2mp_discover_rsp *h = frm->ptr;
1093 uint16_t mtu = btohs(h->mtu);
1094 uint8_t *octet = (uint8_t *)&(h->mask);
1098 printf("Discover rsp: mtu/mps %d ", mtu);
1105 mask = get_le16(octet);
1106 printf(" 0x%4.4x", mask);
1108 extension = octet[1] & 0x80;
1110 } while ((extension != 0) && (len >= 2));
1115 a2mp_ctrl_list_dump(level + 1, (struct a2mp_ctrl *) octet, len);
1119 static inline void a2mp_change_notify(int level, struct frame *frm, uint16_t len)
1121 struct a2mp_ctrl *list = frm->ptr;
1123 printf("Change Notify\n");
1126 a2mp_ctrl_list_dump(level + 1, list, len);
1130 static inline void a2mp_change_rsp(int level, struct frame *frm)
1132 printf("Change Response\n");
1135 static inline void a2mp_info_req(int level, struct frame *frm)
1137 struct a2mp_info_req *h = frm->ptr;
1139 printf("Get Info req: id %d\n", h->id);
1142 static inline void a2mp_info_rsp(int level, struct frame *frm)
1144 struct a2mp_info_rsp *h = frm->ptr;
1146 printf("Get Info rsp: id %d status %d (%s)\n",
1147 h->id, h->status, a2mpstatus2str(h->status));
1149 p_indent(level + 1, 0);
1150 printf("Total bandwidth %d\n", btohl(h->total_bw));
1151 p_indent(level + 1, 0);
1152 printf("Max guaranteed bandwidth %d\n", btohl(h->max_bw));
1153 p_indent(level + 1, 0);
1154 printf("Min latency %d\n", btohl(h->min_latency));
1155 p_indent(level + 1, 0);
1156 printf("Pal capabilities 0x%4.4x\n", btohs(h->pal_caps));
1157 p_indent(level + 1, 0);
1158 printf("Assoc size %d\n", btohs(h->assoc_size));
1161 static inline void a2mp_assoc_req(int level, struct frame *frm)
1163 struct a2mp_assoc_req *h = frm->ptr;
1165 printf("Get AMP Assoc req: id %d\n", h->id);
1168 static inline void a2mp_assoc_rsp(int level, struct frame *frm, uint16_t len)
1170 struct a2mp_assoc_rsp *h = frm->ptr;
1172 printf("Get AMP Assoc rsp: id %d status (%d) %s\n",
1173 h->id, h->status, a2mpstatus2str(h->status));
1174 amp_assoc_dump(level + 1, h->assoc_data, len - sizeof(*h));
1177 static inline void a2mp_create_req(int level, struct frame *frm, uint16_t len)
1179 struct a2mp_create_req *h = frm->ptr;
1181 printf("Create Physical Link req: local id %d remote id %d\n",
1182 h->local_id, h->remote_id);
1183 amp_assoc_dump(level + 1, h->assoc_data, len - sizeof(*h));
1186 static inline void a2mp_create_rsp(int level, struct frame *frm)
1188 struct a2mp_create_rsp *h = frm->ptr;
1190 printf("Create Physical Link rsp: local id %d remote id %d status %d\n",
1191 h->local_id, h->remote_id, h->status);
1192 p_indent(level+1, 0);
1193 printf("%s\n", a2mpcplstatus2str(h->status));
1196 static inline void a2mp_disconn_req(int level, struct frame *frm)
1198 struct a2mp_disconn_req *h = frm->ptr;
1200 printf("Disconnect Physical Link req: local id %d remote id %d\n",
1201 h->local_id, h->remote_id);
1204 static inline void a2mp_disconn_rsp(int level, struct frame *frm)
1206 struct a2mp_disconn_rsp *h = frm->ptr;
1208 printf("Disconnect Physical Link rsp: local id %d remote id %d status %d\n",
1209 h->local_id, h->remote_id, h->status);
1210 p_indent(level+1, 0);
1211 printf("%s\n", a2mpdplstatus2str(h->status));
1214 static void l2cap_parse(int level, struct frame *frm)
1216 l2cap_hdr *hdr = (void *)frm->ptr;
1217 uint16_t dlen = btohs(hdr->len);
1218 uint16_t cid = btohs(hdr->cid);
1221 frm->ptr += L2CAP_HDR_SIZE;
1222 frm->len -= L2CAP_HDR_SIZE;
1225 /* Signaling channel */
1227 while (frm->len >= L2CAP_CMD_HDR_SIZE) {
1228 l2cap_cmd_hdr *hdr = frm->ptr;
1230 frm->ptr += L2CAP_CMD_HDR_SIZE;
1231 frm->len -= L2CAP_CMD_HDR_SIZE;
1233 if (!p_filter(FILT_L2CAP)) {
1234 p_indent(level, frm);
1235 printf("L2CAP(s): ");
1238 switch (hdr->code) {
1239 case L2CAP_COMMAND_REJ:
1240 command_rej(level, frm);
1243 case L2CAP_CONN_REQ:
1244 conn_req(level, frm);
1247 case L2CAP_CONN_RSP:
1248 conn_rsp(level, frm);
1251 case L2CAP_CONF_REQ:
1252 conf_req(level, hdr, frm);
1255 case L2CAP_CONF_RSP:
1256 conf_rsp(level, hdr, frm);
1259 case L2CAP_DISCONN_REQ:
1260 disconn_req(level, frm);
1263 case L2CAP_DISCONN_RSP:
1264 disconn_rsp(level, frm);
1267 case L2CAP_ECHO_REQ:
1268 echo_req(level, hdr, frm);
1271 case L2CAP_ECHO_RSP:
1272 echo_rsp(level, hdr, frm);
1275 case L2CAP_INFO_REQ:
1276 info_req(level, hdr, frm);
1279 case L2CAP_INFO_RSP:
1280 info_rsp(level, hdr, frm);
1283 case L2CAP_CREATE_REQ:
1284 create_req(level, hdr, frm);
1287 case L2CAP_CREATE_RSP:
1288 create_rsp(level, hdr, frm);
1291 case L2CAP_MOVE_REQ:
1292 move_req(level, hdr, frm);
1295 case L2CAP_MOVE_RSP:
1296 move_rsp(level, hdr, frm);
1299 case L2CAP_MOVE_CFM:
1300 move_cfm(level, hdr, frm);
1303 case L2CAP_MOVE_CFM_RSP:
1304 move_cfm_rsp(level, hdr, frm);
1308 if (p_filter(FILT_L2CAP))
1310 printf("code 0x%2.2x ident %d len %d\n",
1311 hdr->code, hdr->ident, btohs(hdr->len));
1312 raw_dump(level, frm);
1315 if (frm->len > btohs(hdr->len)) {
1316 frm->len -= btohs(hdr->len);
1317 frm->ptr += btohs(hdr->len);
1321 } else if (cid == 0x2) {
1322 /* Connectionless channel */
1324 if (p_filter(FILT_L2CAP))
1327 psm = get_le16(frm->ptr);
1331 p_indent(level, frm);
1332 printf("L2CAP(c): len %d psm %d\n", dlen, psm);
1333 raw_dump(level, frm);
1334 } else if (cid == 0x3) {
1335 /* AMP Manager channel */
1337 if (p_filter(FILT_A2MP))
1340 /* Adjust for ERTM control bytes */
1344 while (frm->len >= A2MP_HDR_SIZE) {
1345 struct a2mp_hdr *hdr = frm->ptr;
1347 frm->ptr += A2MP_HDR_SIZE;
1348 frm->len -= A2MP_HDR_SIZE;
1350 p_indent(level, frm);
1353 switch (hdr->code) {
1354 case A2MP_COMMAND_REJ:
1355 a2mp_command_rej(level, frm);
1357 case A2MP_DISCOVER_REQ:
1358 a2mp_discover_req(level, frm, btohs(hdr->len));
1360 case A2MP_DISCOVER_RSP:
1361 a2mp_discover_rsp(level, frm, btohs(hdr->len));
1363 case A2MP_CHANGE_NOTIFY:
1364 a2mp_change_notify(level, frm, btohs(hdr->len));
1366 case A2MP_CHANGE_RSP:
1367 a2mp_change_rsp(level, frm);
1370 a2mp_info_req(level, frm);
1373 a2mp_info_rsp(level, frm);
1375 case A2MP_ASSOC_REQ:
1376 a2mp_assoc_req(level, frm);
1378 case A2MP_ASSOC_RSP:
1379 a2mp_assoc_rsp(level, frm, btohs(hdr->len));
1381 case A2MP_CREATE_REQ:
1382 a2mp_create_req(level, frm, btohs(hdr->len));
1384 case A2MP_CREATE_RSP:
1385 a2mp_create_rsp(level, frm);
1387 case A2MP_DISCONN_REQ:
1388 a2mp_disconn_req(level, frm);
1390 case A2MP_DISCONN_RSP:
1391 a2mp_disconn_rsp(level, frm);
1394 printf("code 0x%2.2x ident %d len %d\n",
1395 hdr->code, hdr->ident, btohs(hdr->len));
1396 raw_dump(level, frm);
1398 if (frm->len > btohs(hdr->len)) {
1399 frm->len -= btohs(hdr->len);
1400 frm->ptr += btohs(hdr->len);
1404 } else if (cid == 0x04) {
1405 if (!p_filter(FILT_ATT))
1406 att_dump(level, frm);
1408 raw_dump(level + 1, frm);
1409 } else if (cid == 0x06) {
1410 if (!p_filter(FILT_SMP))
1411 smp_dump(level, frm);
1413 raw_dump(level + 1, frm);
1415 /* Connection oriented channel */
1417 uint8_t mode = get_mode(!frm->in, frm->handle, cid);
1418 uint8_t ext_ctrl = get_ext_ctrl(!frm->in, frm->handle, cid);
1419 uint16_t psm = get_psm(!frm->in, frm->handle, cid);
1421 uint32_t proto, ctrl = 0;
1424 frm->num = get_num(!frm->in, frm->handle, cid);
1428 ctrl = get_val(frm->ptr, 4);
1432 ctrl = get_val(frm->ptr, 2);
1436 fcs = get_le16(frm->ptr + frm->len);
1439 if (!p_filter(FILT_L2CAP)) {
1440 p_indent(level, frm);
1441 printf("L2CAP(d): cid 0x%4.4x len %d", cid, dlen);
1444 printf(" ext_ctrl 0x%8.8x fcs 0x%4.4x", ctrl, fcs);
1446 printf(" ctrl 0x%4.4x fcs 0x%4.4x", ctrl, fcs);
1449 printf(" [psm %d]\n", psm);
1453 l2cap_ctrl_ext_parse(level, frm, ctrl);
1455 l2cap_ctrl_parse(level, frm, ctrl);
1463 if (!p_filter(FILT_SDP))
1464 sdp_dump(level + 1, frm);
1466 raw_dump(level + 1, frm);
1470 if (!p_filter(FILT_RFCOMM))
1471 rfcomm_dump(level, frm);
1473 raw_dump(level + 1, frm);
1477 if (!p_filter(FILT_BNEP))
1478 bnep_dump(level, frm);
1480 raw_dump(level + 1, frm);
1485 if (!p_filter(FILT_HIDP))
1486 hidp_dump(level, frm);
1488 raw_dump(level + 1, frm);
1493 if (!p_filter(FILT_AVCTP))
1494 avctp_dump(level, frm, psm);
1496 raw_dump(level + 1, frm);
1500 if (!p_filter(FILT_AVDTP))
1501 avdtp_dump(level, frm);
1503 raw_dump(level + 1, frm);
1507 if (!p_filter(FILT_ATT))
1508 att_dump(level, frm);
1510 raw_dump(level + 1, frm);
1514 proto = get_proto(frm->handle, psm, 0);
1518 if (!p_filter(FILT_CMTP))
1519 cmtp_dump(level, frm);
1521 raw_dump(level + 1, frm);
1524 case SDP_UUID_HARDCOPY_CONTROL_CHANNEL:
1525 if (!p_filter(FILT_HCRP))
1526 hcrp_dump(level, frm);
1528 raw_dump(level + 1, frm);
1532 if (!p_filter(FILT_OBEX))
1533 obex_dump(level, frm);
1535 raw_dump(level + 1, frm);
1539 if (p_filter(FILT_L2CAP))
1542 raw_dump(level, frm);
1550 void l2cap_dump(int level, struct frame *frm)
1556 if ((frm->flags & ACL_START) || frm->flags == ACL_START_NO_FLUSH) {
1558 dlen = btohs(hdr->len);
1560 if (dlen + L2CAP_HDR_SIZE < (int) frm->len) {
1562 raw_dump(level,frm);
1566 if ((int) frm->len == (dlen + L2CAP_HDR_SIZE)) {
1567 /* Complete frame */
1568 l2cap_parse(level, frm);
1572 if (!(fr = get_frame(frm->handle))) {
1573 fprintf(stderr, "Not enough connection handles\n");
1574 raw_dump(level, frm);
1581 if (!(fr->data = malloc(dlen + L2CAP_HDR_SIZE))) {
1582 perror("Can't allocate L2CAP reassembly buffer");
1585 memcpy(fr->data, frm->ptr, frm->len);
1586 fr->data_len = dlen + L2CAP_HDR_SIZE;
1589 fr->dev_id = frm->dev_id;
1592 fr->handle = frm->handle;
1595 fr->dlci = frm->dlci;
1596 fr->channel = frm->channel;
1597 fr->pppdump_fd = frm->pppdump_fd;
1598 fr->audio_fd = frm->audio_fd;
1600 if (!(fr = get_frame(frm->handle))) {
1601 fprintf(stderr, "Not enough connection handles\n");
1602 raw_dump(level, frm);
1607 /* Unexpected fragment */
1608 raw_dump(level, frm);
1612 if (frm->len > (fr->data_len - fr->len)) {
1614 raw_dump(level, frm);
1615 free(fr->data); fr->data = NULL;
1619 memcpy(fr->data + fr->len, frm->ptr, frm->len);
1620 fr->len += frm->len;
1622 if (fr->len == fr->data_len) {
1623 /* Complete frame */
1624 l2cap_parse(level, fr);
1626 free(fr->data); fr->data = NULL;
1632 void l2cap_clear(uint16_t handle)