1 /*
2 *
3 * BlueZ - Bluetooth protocol stack for Linux
4 *
5 * Copyright (C) 2001-2002 Wayne Lee <waynelee@qualcomm.com>
6 * Copyright (C) 2003-2007 Marcel Holtmann <marcel@holtmann.org>
7 *
8 *
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.
13 *
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.
18 *
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
22 *
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdio.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38
39 #include <bluetooth/bluetooth.h>
40
41 #include "parser.h"
42 #include "rfcomm.h"
43 #include "sdp.h"
44
45 static char *cr_str[] = {
46 "RSP",
47 "CMD"
48 };
49
50 #define CR_STR(mcc_head) cr_str[mcc_head->type.cr]
51 #define GET_DLCI(addr) ((addr.server_chn << 1) | (addr.d & 1))
52
print_rfcomm_hdr(long_frame_head * head,uint8_t * ptr,int len)53 static void print_rfcomm_hdr(long_frame_head* head, uint8_t *ptr, int len)
54 {
55 address_field addr = head->addr;
56 uint8_t ctr = head->control;
57 uint16_t ilen = head->length.bits.len;
58 uint8_t ctr_type,pf,dlci,fcs;
59
60 dlci = GET_DLCI(addr);
61 pf = GET_PF(ctr);
62 ctr_type = CLR_PF(ctr);
63 fcs = *(ptr + len - 1);
64
65 printf("cr %d dlci %d pf %d ilen %d fcs 0x%x ", addr.cr, dlci, pf, ilen, fcs);
66 }
67
print_mcc(mcc_long_frame_head * mcc_head)68 static void print_mcc(mcc_long_frame_head* mcc_head)
69 {
70 printf("mcc_len %d\n", mcc_head->length.bits.len);
71 }
72
mcc_test(int level,uint8_t * ptr,int len,long_frame_head * head,mcc_long_frame_head * mcc_head)73 static inline void mcc_test(int level, uint8_t *ptr, int len,
74 long_frame_head *head, mcc_long_frame_head *mcc_head)
75 {
76 printf("TEST %s: ", CR_STR(mcc_head));
77 print_rfcomm_hdr(head, ptr, len);
78 print_mcc(mcc_head);
79 }
mcc_fcon(int level,uint8_t * ptr,int len,long_frame_head * head,mcc_long_frame_head * mcc_head)80 static inline void mcc_fcon(int level, uint8_t *ptr, int len,
81 long_frame_head *head, mcc_long_frame_head *mcc_head)
82 {
83 printf("FCON %s: ", CR_STR(mcc_head));
84 print_rfcomm_hdr(head, ptr, len);
85 print_mcc(mcc_head);
86 }
87
mcc_fcoff(int level,uint8_t * ptr,int len,long_frame_head * head,mcc_long_frame_head * mcc_head)88 static inline void mcc_fcoff(int level, uint8_t *ptr, int len,
89 long_frame_head *head, mcc_long_frame_head *mcc_head)
90 {
91 printf("FCOFF %s: ", CR_STR(mcc_head));
92 print_rfcomm_hdr(head, ptr, len);
93 print_mcc(mcc_head);
94 }
95
mcc_msc(int level,uint8_t * ptr,int len,long_frame_head * head,mcc_long_frame_head * mcc_head)96 static inline void mcc_msc(int level, uint8_t *ptr, int len,
97 long_frame_head *head, mcc_long_frame_head *mcc_head)
98 {
99 msc_msg *msc = (void*) (ptr - STRUCT_END(msc_msg, mcc_s_head));
100
101 printf("MSC %s: ", CR_STR(mcc_head));
102 print_rfcomm_hdr(head, ptr, len);
103 print_mcc(mcc_head);
104 p_indent(level, 0);
105 printf("dlci %d fc %d rtc %d rtr %d ic %d dv %d",
106 GET_DLCI(msc->dlci), msc->v24_sigs.fc, msc->v24_sigs.rtc,
107 msc->v24_sigs.rtr, msc->v24_sigs.ic, msc->v24_sigs.dv );
108
109 /* Assuming that break_signals field is _not declared_ in struct msc_msg... */
110 if (len > STRUCT_OFFSET(msc_msg, fcs) - STRUCT_END(msc_msg, v24_sigs)) {
111 break_signals *brk = (break_signals *)
112 (ptr + STRUCT_END(msc_msg, v24_sigs));
113 printf(" b1 %d b2 %d b3 %d len %d\n",
114 brk->b1, brk->b2, brk->b3, brk->len);
115 } else
116 printf("\n");
117 }
118
mcc_rpn(int level,uint8_t * ptr,int len,long_frame_head * head,mcc_long_frame_head * mcc_head)119 static inline void mcc_rpn(int level, uint8_t *ptr, int len,
120 long_frame_head *head, mcc_long_frame_head *mcc_head)
121 {
122 rpn_msg *rpn = (void *) (ptr - STRUCT_END(rpn_msg, mcc_s_head));
123
124 printf("RPN %s: ", CR_STR(mcc_head));
125 print_rfcomm_hdr(head, ptr, len);
126 print_mcc(mcc_head);
127
128 p_indent(level, 0);
129 printf("dlci %d ", GET_DLCI(rpn->dlci));
130
131 /* Assuming that rpn_val is _declared_ as a member of rpn_msg... */
132 if (len <= STRUCT_OFFSET(rpn_msg, rpn_val) - STRUCT_END(rpn_msg, mcc_s_head)) {
133 printf("\n");
134 return;
135 }
136
137 printf("br %d db %d sb %d p %d pt %d xi %d xo %d\n",
138 rpn->rpn_val.bit_rate, rpn->rpn_val.data_bits,
139 rpn->rpn_val.stop_bit, rpn->rpn_val.parity,
140 rpn->rpn_val.parity_type, rpn->rpn_val.xon_input,
141 rpn->rpn_val.xon_output);
142
143 p_indent(level, 0);
144 printf("rtri %d rtro %d rtci %d rtco %d xon %d xoff %d pm 0x%04x\n",
145 rpn->rpn_val.rtr_input, rpn->rpn_val.rtr_output,
146 rpn->rpn_val.rtc_input, rpn->rpn_val.rtc_output,
147 rpn->rpn_val.xon, rpn->rpn_val.xoff, btohs(rpn->rpn_val.pm));
148 }
149
mcc_rls(int level,uint8_t * ptr,int len,long_frame_head * head,mcc_long_frame_head * mcc_head)150 static inline void mcc_rls(int level, uint8_t *ptr, int len,
151 long_frame_head *head, mcc_long_frame_head *mcc_head)
152 {
153 rls_msg* rls = (void*) (ptr - STRUCT_END(rls_msg, mcc_s_head));
154
155 printf("RLS %s: ", CR_STR(mcc_head));
156 print_rfcomm_hdr(head, ptr, len);
157 print_mcc(mcc_head);
158 printf("dlci %d error: %d", GET_DLCI(rls->dlci), rls->error);
159 }
160
mcc_pn(int level,uint8_t * ptr,int len,long_frame_head * head,mcc_long_frame_head * mcc_head)161 static inline void mcc_pn(int level, uint8_t *ptr, int len,
162 long_frame_head *head, mcc_long_frame_head *mcc_head)
163 {
164 pn_msg *pn = (void*) (ptr - STRUCT_END(pn_msg, mcc_s_head));
165
166 printf("PN %s: ", CR_STR(mcc_head));
167 print_rfcomm_hdr(head, ptr, len);
168 print_mcc(mcc_head);
169
170 p_indent(level, 0);
171 printf("dlci %d frame_type %d credit_flow %d pri %d ack_timer %d\n",
172 pn->dlci, pn->frame_type, pn->credit_flow, pn->prior, pn->ack_timer);
173 p_indent(level, 0);
174 printf("frame_size %d max_retrans %d credits %d\n",
175 btohs(pn->frame_size), pn->max_nbrof_retrans, pn->credits);
176 }
177
mcc_nsc(int level,uint8_t * ptr,int len,long_frame_head * head,mcc_long_frame_head * mcc_head)178 static inline void mcc_nsc(int level, uint8_t *ptr, int len,
179 long_frame_head *head, mcc_long_frame_head *mcc_head)
180 {
181
182 nsc_msg *nsc = (void*) (ptr - STRUCT_END(nsc_msg, mcc_s_head));
183
184 printf("NSC %s: ", CR_STR(mcc_head));
185 print_rfcomm_hdr(head, ptr, len);
186 print_mcc(mcc_head);
187
188 p_indent(level, 0);
189 printf("cr %d, mcc_cmd_type %x\n",
190 nsc->command_type.cr, nsc->command_type.type );
191 }
192
mcc_frame(int level,struct frame * frm,long_frame_head * head)193 static inline void mcc_frame(int level, struct frame *frm, long_frame_head *head)
194 {
195 mcc_short_frame_head *mcc_short_head_p = frm->ptr;
196 mcc_long_frame_head mcc_head;
197 uint8_t hdr_size;
198
199 if ( mcc_short_head_p->length.ea == EA ) {
200 mcc_head.type = mcc_short_head_p->type;
201 mcc_head.length.bits.len = mcc_short_head_p->length.len;
202 hdr_size = sizeof(mcc_short_frame_head);
203 } else {
204 mcc_head = *(mcc_long_frame_head *)frm->ptr;
205 mcc_head.length.val = btohs(mcc_head.length.val);
206 hdr_size = sizeof(mcc_long_frame_head);
207 }
208
209 frm->ptr += hdr_size;
210 frm->len -= hdr_size;
211
212 p_indent(level, frm);
213 printf("RFCOMM(s): ");
214
215 switch (mcc_head.type.type) {
216 case TEST:
217 mcc_test(level, frm->ptr, frm->len, head, &mcc_head);
218 raw_dump(level, frm);
219 break;
220 case FCON:
221 mcc_fcon(level, frm->ptr, frm->len, head, &mcc_head);
222 break;
223 case FCOFF:
224 mcc_fcoff(level, frm->ptr, frm->len, head, &mcc_head);
225 break;
226 case MSC:
227 mcc_msc(level, frm->ptr, frm->len, head, &mcc_head);
228 break;
229 case RPN:
230 mcc_rpn(level, frm->ptr, frm->len, head, &mcc_head);
231 break;
232 case RLS:
233 mcc_rls(level, frm->ptr, frm->len, head, &mcc_head);
234 break;
235 case PN:
236 mcc_pn(level, frm->ptr, frm->len, head, &mcc_head);
237 break;
238 case NSC:
239 mcc_nsc(level, frm->ptr, frm->len, head, &mcc_head);
240 break;
241 default:
242 printf("MCC message type 0x%02x: ", mcc_head.type.type);
243 print_rfcomm_hdr(head, frm->ptr, frm->len);
244 printf("\n");
245
246 frm->len--;
247 raw_dump(level, frm);
248 }
249 }
250
uih_frame(int level,struct frame * frm,long_frame_head * head)251 static inline void uih_frame(int level, struct frame *frm, long_frame_head *head)
252 {
253 uint32_t proto;
254
255 if (!head->addr.server_chn) {
256 mcc_frame(level, frm, head);
257 } else {
258 p_indent(level, frm);
259 printf("RFCOMM(d): UIH: ");
260 print_rfcomm_hdr(head, frm->ptr, frm->len);
261 if (GET_PF(head->control)) {
262 printf("credits %d\n", *(uint8_t *)(frm->ptr));
263 frm->ptr++;
264 frm->len--;
265 } else
266 printf("\n");
267
268 frm->len--;
269 frm->dlci = GET_DLCI(head->addr);
270 frm->channel = head->addr.server_chn;
271
272 proto = get_proto(frm->handle, RFCOMM_PSM, frm->channel);
273
274 if (frm->len > 0) {
275 switch (proto) {
276 case SDP_UUID_OBEX:
277 if (!p_filter(FILT_OBEX))
278 obex_dump(level + 1, frm);
279 else
280 raw_dump(level, frm);
281 break;
282
283 case SDP_UUID_LAN_ACCESS_PPP:
284 case SDP_UUID_DIALUP_NETWORKING:
285 if (!p_filter(FILT_PPP))
286 ppp_dump(level + 1, frm);
287 else
288 raw_dump(level, frm);
289 break;
290
291 default:
292 if (p_filter(FILT_RFCOMM))
293 break;
294
295 raw_dump(level, frm);
296 break;
297 }
298 }
299 }
300 }
301
rfcomm_dump(int level,struct frame * frm)302 void rfcomm_dump(int level, struct frame *frm)
303 {
304 uint8_t hdr_size, ctr_type;
305 short_frame_head *short_head_p = (void *) frm->ptr;
306 long_frame_head head;
307
308 if (short_head_p->length.ea == EA) {
309 head.addr = short_head_p->addr;
310 head.control = short_head_p->control;
311 head.length.bits.len = short_head_p->length.len;
312 hdr_size = sizeof(short_frame_head);
313 } else {
314 head = *(long_frame_head *) frm->ptr;
315 head.length.val = btohs(head.length.val);
316 hdr_size = sizeof(long_frame_head);
317 }
318
319 frm->ptr += hdr_size;
320 frm->len -= hdr_size;
321
322 ctr_type = CLR_PF(head.control);
323
324 if (ctr_type == UIH) {
325 uih_frame(level, frm, &head);
326 } else {
327 p_indent(level, frm);
328 printf("RFCOMM(s): ");
329
330 switch (ctr_type) {
331 case SABM:
332 printf("SABM: ");
333 break;
334 case UA:
335 printf("UA: ");
336 break;
337 case DM:
338 printf("DM: ");
339 break;
340 case DISC:
341 printf("DISC: ");
342 del_frame(frm->handle, GET_DLCI(head.addr));
343 break;
344 default:
345 printf("ERR: ");
346 }
347 print_rfcomm_hdr(&head, frm->ptr, frm->len);
348 printf("\n");
349 }
350 }
351