/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2002-2011 Marcel Holtmann <marcel@holtmann.org> * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <errno.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <netinet/in.h> #include "parser.h" #define TABLE_SIZE 10 static struct { uint16_t handle; uint16_t cid; struct frame msg[16]; } table[TABLE_SIZE]; static void add_segment(uint8_t bid, struct frame *frm, int len) { uint16_t handle = frm->handle, cid = frm->cid; struct frame *msg; void *data; int i, pos = -1; if (bid > 15) return; for (i = 0; i < TABLE_SIZE; i++) { if (table[i].handle == handle && table[i].cid == cid) { pos = i; break; } if (pos < 0 && !table[i].handle && !table[i].cid) pos = i; } if (pos < 0) return; table[pos].handle = handle; table[pos].cid = cid; msg = &table[pos].msg[bid]; data = malloc(msg->data_len + len); if (!data) return; if (msg->data_len > 0) memcpy(data, msg->data, msg->data_len); memcpy(data + msg->data_len, frm->ptr, len); free(msg->data); msg->data = data; msg->data_len += len; msg->ptr = msg->data; msg->len = msg->data_len; msg->in = frm->in; msg->ts = frm->ts; msg->handle = handle; msg->cid = cid; } static void free_segment(uint8_t bid, struct frame *frm) { uint16_t handle = frm->handle, cid = frm->cid; struct frame *msg; int i, len = 0, pos = -1; if (bid > 15) return; for (i = 0; i < TABLE_SIZE; i++) if (table[i].handle == handle && table[i].cid == cid) { pos = i; break; } if (pos < 0) return; msg = &table[pos].msg[bid]; if (msg->data) free(msg->data); msg->data = NULL; msg->data_len = 0; for (i = 0; i < 16; i++) len += table[pos].msg[i].data_len; if (!len) { table[pos].handle = 0; table[pos].cid = 0; } } static struct frame *get_segment(uint8_t bid, struct frame *frm) { uint16_t handle = frm->handle, cid = frm->cid; int i; if (bid > 15) return NULL; for (i = 0; i < TABLE_SIZE; i++) if (table[i].handle == handle && table[i].cid == cid) return &table[i].msg[bid]; return NULL; } static char *bst2str(uint8_t bst) { switch (bst) { case 0x00: return "complete CAPI Message"; case 0x01: return "segmented CAPI Message"; case 0x02: return "error"; case 0x03: return "reserved"; default: return "unknown"; } } void cmtp_dump(int level, struct frame *frm) { struct frame *msg; uint8_t hdr, bid; uint16_t len; while (frm->len > 0) { hdr = get_u8(frm); bid = (hdr & 0x3c) >> 2; switch ((hdr & 0xc0) >> 6) { case 0x01: len = get_u8(frm); break; case 0x02: len = htons(get_u16(frm)); break; default: len = 0; break; } p_indent(level, frm); printf("CMTP: %s: id %d len %d\n", bst2str(hdr & 0x03), bid, len); switch (hdr & 0x03) { case 0x00: add_segment(bid, frm, len); msg = get_segment(bid, frm); if (!msg) break; if (!p_filter(FILT_CAPI)) capi_dump(level + 1, msg); else raw_dump(level, msg); free_segment(bid, frm); break; case 0x01: add_segment(bid, frm, len); break; default: free_segment(bid, frm); break; } frm->ptr += len; frm->len -= len; } }