text: /*
   *
   *  BlueZ - Bluetooth protocol stack for Linux
   *
   *  Copyright (C) 2000-2002  Maxim Krasnyansky <maxk@qualcomm.com>
   *  Copyright (C) 2003-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
   *
   */
  
  #ifndef __PARSER_H
  #define __PARSER_H
  
  #include <time.h>
  #include <sys/time.h>
  #include <netinet/in.h>
  
  #include "lib/bluetooth.h"
  #include "src/shared/util.h"
  
  struct frame {
  	void		*data;
  	uint32_t	data_len;
  	void		*ptr;
  	uint32_t	len;
  	uint16_t	dev_id;
  	uint8_t		in;
  	uint8_t		master;
  	uint16_t	handle;
  	uint16_t	cid;
  	uint16_t	num;
  	uint8_t		dlci;
  	uint8_t		channel;
  	unsigned long	flags;
  	struct timeval	ts;
  	int		pppdump_fd;
  	int		audio_fd;
  };
  
  /* Parser flags */
  #define DUMP_WIDTH	20
  
  #define DUMP_ASCII	0x0001
  #define DUMP_HEX	0x0002
  #define DUMP_EXT	0x0004
  #define DUMP_RAW	0x0008
  #define DUMP_BPA	0x0010
  #define DUMP_TSTAMP	0x0100
  #define DUMP_VERBOSE	0x0200
  #define DUMP_BTSNOOP	0x1000
  #define DUMP_PKTLOG	0x2000
  #define DUMP_NOVENDOR	0x4000
  #define DUMP_TYPE_MASK	(DUMP_ASCII | DUMP_HEX | DUMP_EXT)
  
  /* Parser filter */
  #define FILT_LMP	0x0001
  #define FILT_HCI	0x0002
  #define FILT_SCO	0x0004
  #define FILT_L2CAP	0x0008
  #define FILT_RFCOMM	0x0010
  #define FILT_SDP	0x0020
  #define FILT_BNEP	0x0040
  #define FILT_CMTP	0x0080
  #define FILT_HIDP	0x0100
  #define FILT_HCRP	0x0200
  #define FILT_AVDTP	0x0400
  #define FILT_AVCTP	0x0800
  #define FILT_ATT 	0x1000
  #define FILT_SMP	0x2000
  #define FILT_A2MP	0x4000
  
  #define FILT_OBEX	0x00010000
  #define FILT_CAPI	0x00020000
  #define FILT_PPP	0x00040000
  #define FILT_SAP	0x00080000
  #define FILT_ERICSSON	0x10000000
  #define FILT_CSR	0x1000000a
  #define FILT_DGA	0x1000000c
  
  #define STRUCT_OFFSET(type, member)  ((uint8_t *)&(((type *)NULL)->member) - \
                                       (uint8_t *)((type *)NULL))
  
  #define STRUCT_END(type, member)     (STRUCT_OFFSET(type, member) + \
                                       sizeof(((type *)NULL)->member))
  
  #define DEFAULT_COMPID	65535
  
  struct parser_t {
  	unsigned long flags;
  	unsigned long filter;
  	unsigned short defpsm;
  	unsigned short defcompid;
  	int state;
  	int pppdump_fd;
  	int audio_fd;
  };
  
  extern struct parser_t parser;
  
  void init_parser(unsigned long flags, unsigned long filter,
  		unsigned short defpsm, unsigned short defcompid,
  		int pppdump_fd, int audio_fd);
  
  static inline int p_filter(unsigned long f)
  {
  	return !(parser.filter & f);
  }
  
  static inline void p_indent(int level, struct frame *f)
  {
  	if (level < 0) {
  		parser.state = 0;
  		return;
  	}
  
  	if (!parser.state) {
  		if (parser.flags & DUMP_TSTAMP) {
  			if (parser.flags & DUMP_VERBOSE) {
  				struct tm tm;
  				time_t t = f->ts.tv_sec;
  				localtime_r(&t, &tm);
  				printf("%04d-%02d-%02d %02d:%02d:%02d.%06lu ",
  					tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
  					tm.tm_hour, tm.tm_min, tm.tm_sec, f->ts.tv_usec);
  			} else
  				printf("%8lu.%06lu ", f->ts.tv_sec, f->ts.tv_usec);
  		}
  		printf("%c ", (f->in ? '>' : '<'));
  		parser.state = 1;
  	} else 
  		printf("  ");
  
  	if (level)
  		printf("%*c", (level*2), ' ');
  }
  
  static inline void p_ba2str(const bdaddr_t *ba, char *str)
  {
  	if (parser.flags & DUMP_NOVENDOR) {
  		uint8_t b[6];
  
  		baswap((bdaddr_t *) b, ba);
  		sprintf(str, "%2.2X:%2.2X:%2.2X:*:*:*", b[0], b[1], b[2]);
  	} else
  		ba2str(ba, str);
  }
  
  /* get_uXX functions do byte swaping */
  
  static inline uint8_t p_get_u8(struct frame *frm)
  {
  	uint8_t *u8_ptr = frm->ptr;
  	frm->ptr += 1;
  	frm->len -= 1;
  	return *u8_ptr;
  }
  
  static inline uint16_t p_get_u16(struct frame *frm)
  {
  	uint16_t *u16_ptr = frm->ptr;
  	frm->ptr += 2;
  	frm->len -= 2;
  	return get_be16(u16_ptr);
  }
  
  static inline uint32_t p_get_u32(struct frame *frm)
  {
  	uint32_t *u32_ptr = frm->ptr;
  	frm->ptr += 4;
  	frm->len -= 4;
  	return get_be32(u32_ptr);
  }
  
  static inline uint64_t p_get_u64(struct frame *frm)
  {
  	uint64_t *u64_ptr = frm->ptr;
  	uint64_t u64 = get_unaligned(u64_ptr), tmp;
  	frm->ptr += 8;
  	frm->len -= 8;
  	tmp = ntohl(u64 & 0xffffffff);
  	u64 = (tmp << 32) | ntohl(u64 >> 32);
  	return u64;
  }
  
  static inline void p_get_u128(struct frame *frm, uint64_t *l, uint64_t *h)
  {
  	*h = p_get_u64(frm);
  	*l = p_get_u64(frm);
  }
  
  char *get_uuid_name(int uuid);
  
  void set_proto(uint16_t handle, uint16_t psm, uint8_t channel, uint32_t proto);
  uint32_t get_proto(uint16_t handle, uint16_t psm, uint8_t channel);
  
  struct frame *add_frame(struct frame *frm);
  void del_frame(uint16_t handle, uint8_t dlci);
  
  uint8_t get_opcode(uint16_t handle, uint8_t dlci);
  void set_opcode(uint16_t handle, uint8_t dlci, uint8_t opcode);
  
  uint8_t get_status(uint16_t handle, uint8_t dlci);
  void set_status(uint16_t handle, uint8_t dlci, uint8_t status);
  
  void l2cap_clear(uint16_t handle);
  
  void ascii_dump(int level, struct frame *frm, int num);
  void hex_dump(int level, struct frame *frm, int num);
  void ext_dump(int level, struct frame *frm, int num);
  void raw_dump(int level, struct frame *frm);
  void raw_ndump(int level, struct frame *frm, int num);
  
  void lmp_dump(int level, struct frame *frm);
  void hci_dump(int level, struct frame *frm);
  void l2cap_dump(int level, struct frame *frm);
  void rfcomm_dump(int level, struct frame *frm);
  void sdp_dump(int level, struct frame *frm);
  void bnep_dump(int level, struct frame *frm);
  void cmtp_dump(int level, struct frame *frm);
  void hidp_dump(int level, struct frame *frm);
  void hcrp_dump(int level, struct frame *frm);
  void avdtp_dump(int level, struct frame *frm);
  void avctp_dump(int level, struct frame *frm, uint16_t psm);
  void avrcp_dump(int level, struct frame *frm, uint8_t hdr, uint16_t psm);
  void att_dump(int level, struct frame *frm);
  void smp_dump(int level, struct frame *frm);
  void sap_dump(int level, struct frame *frm);
  
  void obex_dump(int level, struct frame *frm);
  void capi_dump(int level, struct frame *frm);
  void ppp_dump(int level, struct frame *frm);
  void arp_dump(int level, struct frame *frm);
  void ip_dump(int level, struct frame *frm);
  void ericsson_dump(int level, struct frame *frm);
  void csr_dump(int level, struct frame *frm);
  void bpa_dump(int level, struct frame *frm);
  
  void amp_assoc_dump(int level, uint8_t *assoc, uint16_t len);
  
  static inline void parse(struct frame *frm)
  {
  	p_indent(-1, NULL);
  	if (parser.flags & DUMP_RAW)
  		raw_dump(0, frm);
  	else
  		hci_dump(0, frm);
  	fflush(stdout);
  }
  
  #endif /* __PARSER_H */
  