/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2011 Marcel Holtmann * * * 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 #endif #include #include #include #include #include #include "parser.h" #define PPP_U8(frm) (get_u8(frm)) #define PPP_U16(frm) (btohs(htons(get_u16(frm)))) #define PPP_U32(frm) (btohl(htonl(get_u32(frm)))) static int ppp_traffic = 0; static unsigned char ppp_magic1[] = { 0x7e, 0xff, 0x03, 0xc0, 0x21 }; static unsigned char ppp_magic2[] = { 0x7e, 0xff, 0x7d, 0x23, 0xc0, 0x21 }; static unsigned char ppp_magic3[] = { 0x7e, 0x7d, 0xdf, 0x7d, 0x23, 0xc0, 0x21 }; static inline int check_for_ppp_traffic(unsigned char *data, int size) { unsigned int i; for (i = 0; i < size - sizeof(ppp_magic1); i++) if (!memcmp(data + i, ppp_magic1, sizeof(ppp_magic1))) { ppp_traffic = 1; return i; } for (i = 0; i < size - sizeof(ppp_magic2); i++) if (!memcmp(data + i, ppp_magic2, sizeof(ppp_magic2))) { ppp_traffic = 1; return i; } for (i = 0; i < size - sizeof(ppp_magic3); i++) if (!memcmp(data + i, ppp_magic3, sizeof(ppp_magic3))) { ppp_traffic = 1; return i; } return -1; } static inline char *dir2str(uint8_t in) { return in ? "DCE" : "DTE"; } static inline char *proto2str(uint16_t proto) { switch (proto) { case 0x0001: return "Padding Protocol"; case 0x0021: return "IP"; case 0x8021: return "IP Control Protocol"; case 0x80fd: return "Compression Control Protocol"; case 0xc021: return "Link Control Protocol"; case 0xc023: return "Password Authentication Protocol"; case 0xc025: return "Link Quality Report"; case 0xc223: return "Challenge Handshake Authentication Protocol"; default: return "Unknown Protocol"; } } static void hdlc_dump(int level, struct frame *frm) { uint8_t addr = get_u8(frm); uint8_t ctrl = get_u8(frm); uint16_t fcs, proto; fcs = get_unaligned((uint16_t *) (frm->ptr + frm->len - 2)); frm->len -= 2; p_indent(level, frm); if (addr != 0xff || ctrl != 0x03) { frm->ptr -= 2; frm->len += 2; printf("HDLC: %s: len %d fcs 0x%04x\n", dir2str(frm->in), frm->len, fcs); } else printf("HDLC: %s: addr 0x%02x ctrl 0x%02x len %d fcs 0x%04x\n", dir2str(frm->in), addr, ctrl, frm->len, fcs); if (*((uint8_t *) frm->ptr) & 0x80) proto = get_u16(frm); else proto = get_u8(frm); p_indent(level + 1, frm); printf("PPP: %s (0x%04x): len %d\n", proto2str(proto), proto, frm->len); raw_dump(level + 1, frm); } static inline void unslip_frame(int level, struct frame *frm, int len) { struct frame msg; unsigned char *data, *ptr; int i, p = 0; data = malloc(len * 2); if (!data) return; ptr = frm->ptr; for (i = 0; i < len; i++) { if (ptr[i] == 0x7d) { data[p++] = ptr[i + 1] ^ 0x20; i++; } else data[p++] = ptr[i]; } memset(&msg, 0, sizeof(msg)); msg.data = data; msg.data_len = len * 2; msg.ptr = msg.data; msg.len = p; msg.in = frm->in; msg.ts = frm->ts; msg.handle = frm->handle; msg.cid = frm->cid; hdlc_dump(level, &msg); free(data); } void ppp_dump(int level, struct frame *frm) { void *ptr, *end; int err, len, pos = 0; if (frm->pppdump_fd > fileno(stderr)) { unsigned char id; uint16_t len = htons(frm->len); uint32_t ts = htonl(frm->ts.tv_sec & 0xffffffff); id = 0x07; err = write(frm->pppdump_fd, &id, 1); if (err < 0) return; err = write(frm->pppdump_fd, &ts, 4); if (err < 0) return; id = frm->in ? 0x02 : 0x01; err = write(frm->pppdump_fd, &id, 1); if (err < 0) return; err = write(frm->pppdump_fd, &len, 2); if (err < 0) return; err = write(frm->pppdump_fd, frm->ptr, frm->len); if (err < 0) return; } if (!ppp_traffic) { pos = check_for_ppp_traffic(frm->ptr, frm->len); if (pos < 0) { raw_dump(level, frm); return; } if (pos > 0) { raw_ndump(level, frm, pos); frm->ptr += pos; frm->len -= pos; } } frm = add_frame(frm); while (frm->len > 0) { ptr = memchr(frm->ptr, 0x7e, frm->len); if (!ptr) break; if (frm->ptr != ptr) { frm->len -= (ptr - frm->ptr); frm->ptr = ptr; } end = memchr(frm->ptr + 1, 0x7e, frm->len - 1); if (!end) break; len = end - ptr - 1; frm->ptr++; frm->len--; if (len > 0) { unslip_frame(level, frm, len); frm->ptr += len; frm->len -= len; } } }