/* 
 * rfcomm.c --  Implementation of Bluetooth RFCOMM with TS 07.10, 
 *              Serial Port Emulation
 *
 * Copyright (C) 2000  Axis Communications AB
 *
 * Mats Friden <mats.friden@axis.com>
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Id: rfcomm.c,v 1.64 2000/10/27 11:59:24 mattias Exp $
 *
 */

#define __NO_VERSION__ /* don't define kernel_version in module.h */

#ifdef __KERNEL__ 
#include <linux/malloc.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/sched.h>

#include <linux/bluetooth/rfcomm.h>
#include <linux/bluetooth/btmem.h>
#include <linux/bluetooth/l2cap.h>
#include <linux/bluetooth/bluetooth.h>
#else
#include <stdlib.h>
#include <string.h>
#include "include/rfcomm.h"
#include "include/btmem.h"
#include "include/l2cap.h"
#include "include/bluetooth.h"
#endif

/****************** DEBUG CONSTANT AND MACRO SECTION ************************/

/* Defines for the debug macros */

#if DEBUG_RFCOMM_RECEIVE_FLOW
#define D_REC(fmt, args...) printk(RFCOMM_DBG_STR fmt, ## args)
#else
#define D_REC(fmt, args...) 
#endif

#if DEBUG_RFCOMM_SEND_PROCESS
#define D_SND(fmt, args...) printk(RFCOMM_DBG_STR fmt, ## args)
#else
#define D_SND(fmt, args...)
#endif

#if DEBUG_RFCOMM_INTERNAL_SIGNALING
#define D_CTRL(fmt, args...) printk(RFCOMM_DBG_STR fmt, ## args)
#else
#define D_CTRL(fmt, args...)
#endif

#if PRINT_DATA_ENABLE
#define PRINTPKT(str, data, len) print_data(str, data, len)
#else
#define PRINTPKT(str, data, len)
#endif


/****************** CONSTANT AND MACRO SECTION ******************************/

#define GET_BIT(pos,bitfield) ((bitfield[(pos)/32]) & (1 << ((pos) % 32)))
#define SET_BIT(pos,bitfield) ((bitfield[(pos)/32]) |= (1 << ((pos) % 32))) 
#define CLR_BIT(pos,bitfield) ((bitfield[(pos)/32]) &= ((1 << ((pos) % 32)) \
                                                        ^ (~0)))

#define SET_PF(ctr) ((ctr) | (1 << 4)) 
/* Sets the P/F-bit in the control field */
#define CLR_PF(crt) ((crt) & 0xef)
/* clears the P/F-bit in the control field */
#define GET_PF(crt) (((ctr) >> 4) & 0x1)
/* Returns the P/F bit */

#define SHORT_CRC_CHECK 2
/* Used for uih packets */
#define LONG_CRC_CHECK 3
/* Used for all packet exepts for the uih packets */
#define SHORT_HDR 2
/* Short header for short uih packets */
#define LONG_HDR 3
/* and long header for long uih packets */
#define MAX_NBR_OF_TTY 7
/* FIXME: Should thsi one be define here? */
#define SHORT_PAYLOAD_SIZE 127
#define EA 1
/* Used for setting the EA field in different packets, really neccessary? */
#define FCS_SIZE 1
/* Yes the FCS size is only one byte */

#define RFCOMM_MAX_HDR_SIZE 5

/* Values used for the L2CAP configuration process */
#define RFCOMM_MTU 672
/* Default, why should we be different */
#define RFCOMM_QOS 0x01 
/* Best effort */
#define RFCOMM_FLUSH_TIMEOUT 0xffff 
/* Reliable channel, infinite amout of retransmissions */

#define DEF_RFCOMM_MTU 127

/* The values in the control field when sending ordinary rfcomm packets */
#define SABM 0x2f
#define SABM_SIZE 4
#define UA 0x63
#define UA_SIZE 4
#define DM 0x0f
#define DISC 0x43
#define UIH 0xef

/* The values in the type field in a multiplexer command packet */
#define TEST 0x8
#define FCON 0x28
#define FCOFF 0x18
#define MSC 0x38
#define RPN 0x24
#define RLS 0x14
#define PN 0x20
#define NSC 0x4

/* Define of some V.24 signals modem control signals in RFCOMM */
#define FC 0x2
#define RTC 0x4
#define RTR 0x8
#define DV 0x80
/****************** TYPE DEFINITION SECTION *********************************/

/* Typedefinitions of stuctures used for creating and parsing packets, for a
   further description of the structures please se the bluetooth core
   specification part F:1 and the ETSI TS 07.10 specification  */

typedef struct address_field{
	u8 ea:1;
	u8 cr:1;
	u8 d:1;
	u8 server_chn:5;
} address_field;

typedef struct short_length{
	u8 ea:1;
	u8 len:7;
} short_length;

typedef struct long_length{
	u8 ea:1;
	unsigned short len:15;
} long_length;

typedef struct short_frame_head{
	address_field addr;
	u8 control;
	short_length length;
} short_frame_head;

typedef struct short_frame{
	short_frame_head h;
	u8 data[0];
} short_frame;

typedef struct long_frame_head{
	address_field addr;
	u8 control;
	long_length length;
	u8 data[0];
} long_frame_head;

typedef struct long_frame{
	long_frame_head h;
	u8 data[0];
} long_frame;

/* Typedefinitions for structures used for the multiplexer commands */
typedef struct mcc_type{
	u8 ea:1;
	u8 cr:1;
	u8 type:6;
} mcc_type;

typedef struct mcc_short_frame_head{
	mcc_type type;
	short_length length;
	u8 value[0];
} mcc_short_frame_head;

typedef struct mcc_short_frame{
	mcc_short_frame_head h;
	u8 value[0];
} mcc_short_frame;

typedef struct mcc_long_frame_head{
	mcc_type type;
	long_length length;
	u8 value[0];
} mcc_long_frame_head;

typedef struct mcc_long_frame{
	mcc_long_frame_head h;
	u8 value[0];
} mcc_long_frame;

/* MSC-command */
typedef struct v24_signals{
	u8 ea:1;
	u8 fc:1;
	u8 rtc:1;
	u8 rtr:1;
	u8 reserved:2;
	u8 ic:1;
	u8 dv:1;
} v24_sigs;

typedef struct brk_sigs{
	u8 ea:1;
	u8 b1:1;
	u8 b2:1;
	u8 b3:1;
	u8 len:4;
} brk_sigs;

typedef struct msc_msg{
	short_frame_head s_head;
	mcc_short_frame_head mcc_s_head;
	address_field dlci;
	u8 v24_sigs;
	//brk_sigs break_signals;
	u8 fcs;
} msc_msg;

#if 0
/* RPN command */
#define B2400 0
#define B4800 1
#define B7200 2
#define B9600 3
#define B19200 4
#define B38400 5
#define B57600 6
#define B115200 7
#define D230400 8

#endif

#if 0 /* Temporary moved to rfcomm.h during the UnPlugFest */
typedef struct parameter_mask{
	u8 bit_rate:1;
	u8 data_bits:1;
	u8 stop_bit:1;
	u8 parity:1;
	u8 parity_type:1;
	u8 xon_u8:1;
	u8 xoff_u8:1;
	u8 res1:1;
	u8 xon_input:1;
	u8 xon_output:1;
	u8 rtr_input:1;
	u8 rtr_output:1;
	u8 rtc_input:1;
	u8 rtc_output:1;
	u8 res2:2;
} parameter_mask;

typedef struct rpn_values{
	u8 bit_rate;
	u8 data_bits:2;
	u8 stop_bit:1;
	u8 parity:1;
	u8 parity_type:2;
	u8 res1:2;
	u8 xon_input:1;
	u8 xon_output:1;
	u8 rtr_input:1;
	u8 rtr_output:1;
	u8 rtc_input:1;
	u8 rtc_output:1;
	u8 res2:2;
	u8 xon_u8;
	u8 xoff_u8;
	parameter_mask pm;
} rpn_values;
#endif

typedef struct rpn_msg{
	short_frame_head s_head;
	mcc_short_frame_head mcc_s_head;
	address_field dlci;
	rpn_values rpn_val;
	u8 fcs;
} rpn_msg;

/* RLS-command */  
typedef struct rls_msg{
	short_frame_head s_head;
	mcc_short_frame_head mcc_s_head;
	address_field dlci;
	u8 error:4;
	u8 res:4;
	u8 fcs;
} rls_msg;

/* PN-command */
typedef struct pn_msg{
	short_frame_head s_head;
	mcc_short_frame_head mcc_s_head;
/* The res1, res2 and res3 values have to be set to 0 by the sender */
	u8 dlci:6;
	u8 res1:2;
	u8 frame_type:4;
	u8 convergence_layer:4;
	u8 prior:6;
	u8 res2:2;
	u8 ack_timer;
	u32 frame_size:16;
	u8 max_nbrof_retrans;
	u8 win_size:3;
	u8 res3:5;
	u8 fcs;
} pn_msg;

/* NSC-command */
typedef struct nsc_msg{
	short_frame_head s_head;
	mcc_short_frame_head mcc_s_head;
	mcc_type command_type;
	u8 fcs;
} nsc_msg;

/****************** LOCAL FUNCTION DECLARATION SECTION **********************/
static void process_mcc(u8* data, u32 len, rfcomm_con *rfcomm, s32 long_pkt);
static s32 send_ua(rfcomm_con *rfcomm, u8 dlci);
static s32 send_dm(rfcomm_con *rfcomm, s32 dlci);
static s32 send_sabm(rfcomm_con *rfcomm, u32 dlci);
static s32 send_disc(rfcomm_con *rfcomm, u32 dlci);
static s32 send_uih(u8 *data, u32 len, rfcomm_con *rfcomm, u32 dlci);

static s32 send_pn_msg(rfcomm_con *rfcomm, u8 prior, u32 frame_size, u32 dlci, u8 cr);
static s32 send_nsc_msg(rfcomm_con *rfcomm, mcc_type cmd, u8 cr);
static void set_uih_hdr(short_frame *uih_pkt, u8 dlci, u32 len, u8 cr);
static u32 crc_check(u8 *data, u32 length, u8 check_sum);
static u8 crc_calc(u8 *data, u32 length);
static void create_crctable(u8 table[]);
static s32 valid_dlci(u8 dlci);
static rfcomm_con* get_new_rfcomm_con(void);
static rfcomm_con* get_rfcomm_con(u8 line);
static s32 get_connected_dlci(rfcomm_con *rfcomm);

/****************** GLOBAL VARIABLE DECLARATION SECTION *********************/

/****************** LOCAL VARIABLE DECLARATION SECTION **********************/

static u8 crctable[256];
/* The crctable for the FEC field */

rfcomm_con rfcomm_con_list[7];
/* One RFCOMM connection for each bt_tty 0 to 6 */

#ifdef __KERNEL__
static struct wait_queue *rfcomm_disconnect_wq = NULL;
#endif

rpn_values rpn_val;

/****************** FUNCTION DEFINITION SECTION *****************************/

/****************************************************************************
 * Functions reachable outside this file
 ****************************************************************************/

void 
rfcomm_init(void)
{
	s32 i;
	protocol_layer this_layer;

	DSYS("Initialising RFCOMM\n");
	create_crctable(crctable);

	/* Set the confirm and indication functions for the L2CAP-layer */
	this_layer.con_ind = rfcomm_connect_ind;
	this_layer.conf_ind = rfcomm_config_ind;
	this_layer.disc_ind = rfcomm_disconnect_ind;
	this_layer.con_cfm = rfcomm_connect_cfm;
	this_layer.conf_cfm = rfcomm_config_cfm;
	this_layer.disc_cfm = rfcomm_disconnect_cfm;
	this_layer.receive_data = rfcomm_receive_data;

	/* Register RFCOMM in the L2CAP layer*/
	l2cap_register_upper(RFCOMM_LAYER, &this_layer);
 
	/* Initiate the rfcomm objects to not connected */
	for (i = 0; i < MAX_NBR_OF_TTY; i++) {
		s32 j;
		rfcomm_con_list[i].magic = RFCOMM_MAGIC; /* test */
		rfcomm_con_list[i].line = i;
		for (j = 0; j < 62; j++) {
			rfcomm_con_list[i].dlci[j].state = DISCONNECTED;
			rfcomm_con_list[i].dlci[j].mtu = DEF_RFCOMM_MTU;
			rfcomm_con_list[i].dlci[j].initiated = FALSE;
			rfcomm_con_list[i].dlci[j].initiator = FALSE;
		}
		rfcomm_con_list[i].initiator = FALSE;
		rfcomm_con_list[i].l2cap = NULL;
	}

	/* Set the values in the rpn octets */
	rpn_val.bit_rate = 7; /* Irrelevent here */
	rpn_val.data_bits = 3; /* 8 databits */
	rpn_val.stop_bit = 0; /*One stopbit */
	rpn_val.parity = 0;
	rpn_val.parity_type = 0;
	rpn_val.res1 = 0;
	rpn_val.xon_input = 0;
	rpn_val.xon_output = 0;
	rpn_val.rtr_input = 0;
	rpn_val.rtr_output = 0;
	rpn_val.rtc_input = 0;
	rpn_val.rtc_output = 0;
	rpn_val.res2 = 0;
	rpn_val.xon_u8 = 0x11;
	rpn_val.xoff_u8 = 0x13;
	memset(&rpn_val.pm, 0 , 2); /* Set the mask to zero */

}

s32
rfcomm_set_mtu(rfcomm_con *rfcomm, u8 dlci, u32 new_mtu)
{
	if (rfcomm->dlci[dlci].state == DISCONNECTED) {
		rfcomm->dlci[dlci].mtu = new_mtu;
		return 0;
	} else {
		return -1;
	}
}

void 
rfcomm_close(void)
{
	s32 i;
  
	DSYS("Shutting down RFCOMM\n");
	for (i = 0; i < MAX_NBR_OF_TTY; i++) {
		s32 j;
		rfcomm_con_list[i].magic = RFCOMM_MAGIC; /* test */
		rfcomm_con_list[i].line = i;
		for (j = 0; j < 62; j++) {
			rfcomm_con_list[i].dlci[j].state = DISCONNECTED;
			rfcomm_con_list[i].dlci[j].mtu = DEF_RFCOMM_MTU;
			rfcomm_con_list[i].dlci[j].initiated = FALSE;
			rfcomm_con_list[i].dlci[j].initiator = FALSE;
		}
		rfcomm_con_list[i].initiator = FALSE;
		rfcomm_con_list[i].l2cap = NULL;
	}
}

/* This function creates an rfcomm connection over the control channel, 
   DCLI 0 and over DLCI 1 which will be the data channel */
  
u32 
rfcomm_connect_req(u8* bd_addr, s32 server_chn, s32 line)
{
#define FNC "rfcomm_connect_req: "
	rfcomm_con *rfcomm;
	u8 tmp_dlci;
  
	D_CTRL(FNC"server channel:%d, line:%d\n",
	       server_chn, line);

	if (!(rfcomm = get_rfcomm_con(line))) {
		D_ERR(FNC"ERROR: %d is an invalid line\n",
		      line);
		return 0;
	}

	if (rfcomm->dlci[0].state == DISCONNECTED) {
		rfcomm->initiator = TRUE;
	}
	rfcomm->server_chn = server_chn;
	tmp_dlci = (server_chn << 1) | (~rfcomm->initiator & 0x1);
	
	if (!(rfcomm->l2cap)) {
		if (l2ca_connect_req(bd_addr, RFCOMM_LAYER)) {
			D_ERR(FNC"l2ca_connect_req failed\n");
			return 0;
		}
		rfcomm->dlci[0].state = CONNECTING;    
	} else if (!((rfcomm->l2cap)->current_state == OPEN)) {
		D_ERR(FNC"L2CAP_CON exists but is not in OPEN state\n");
		return 0;
	} else if (rfcomm->dlci[0].state != CONNECTED) {
		if (rfcomm->dlci[0].state != DISCONNECTED) {
			D_ERR(FNC"DLCI:0 neither CONNECTED nor DISCONNECTED\n");
			return 0;
		} else {
			rfcomm->dlci[0].state = CONNECTING;
			/* Establish the control channel */
			send_sabm(rfcomm,0);
		}
	} else if (rfcomm->dlci[tmp_dlci].state != DISCONNECTED) {
		D_ERR(FNC"ERROR trying to connect a non DISCONNECTED server channel (%d)\n",server_chn);
		return 0;
	} else {
		rfcomm->dlci[tmp_dlci].state = NEGOTIATING;
		/* must fit i l2cap mtu */
		D_CTRL(FNC"negotiate mtu : %d bytes\n",
		       rfcomm->l2cap->remote_mtu - 5);
		send_pn_msg(rfcomm, 7, rfcomm->dlci[tmp_dlci].mtu,
			    tmp_dlci, TRUE);
	}
	return line;
#undef FNC
}

void 
rfcomm_disconnect_req(u8 line)
{
	rfcomm_con *rfcomm;
	s32 tmp;
	
	if (!(rfcomm = &rfcomm_con_list[line]))
	{
		D_ERR("rfcomm_disconnect_req : no rfcomm con\n");
		return;
	}
	
	tmp = get_connected_dlci(rfcomm);
			
	if (tmp > 0) {
		rfcomm->dlci[tmp].state = DISCONNECTING;
		send_disc(rfcomm, tmp);
#ifdef __KERNEL__
		interruptible_sleep_on(&rfcomm_disconnect_wq);
		l2ca_disconnect_req(rfcomm->l2cap);
		bt_unregister_rfcomm(line);
#endif
	}
}
	

/* The lower protocol layer, L2CAP, indicates that a new connection has been
   established at a lower layer. RFCOMM should ask the control block whether
   to accept or reject the connection and then reply to L2CAP with
   l2cap_connect_rsp. */

void 
rfcomm_connect_ind(l2cap_con *l2cap)
{
	rfcomm_con *rfcomm;
  
	if (!(rfcomm = get_new_rfcomm_con())) {
		D_ERR("rfcomm_connect_ind: error: couldn't find free tty\n");
		return;
	} else {

		if (l2ca_connect_rsp(l2cap, RES_SUCCESS, STAT_NOINFO)) {
			D_ERR("rfcomm_connect_ind: l2ca_connect_rsp failed\n");
			return;
		}
		rfcomm->initiator = FALSE;
		rfcomm->dlci[0].state = CONNECTING;
		rfcomm->l2cap = l2cap;
		l2cap->upper_con = (void*) rfcomm;
	}
}

void 
rfcomm_connect_cfm(l2cap_con *l2cap, s32 status)
{
#define FNC "rfcomm_connect_cfm: "
	s32 i = 0;
	s32 stop = FALSE;
	s32 error = -1;
	rfcomm_con *rfcomm = NULL;
  
	if (status) {
		DSYS(FNC"Connection failed\n");
		bt_rfcomm_connection_ready(error);
		return;
	}

	/* Find the connecting rfcomm_con */
	while ((i < 7) && (!stop)) {
		if ((rfcomm_con_list[i].dlci[0].state == CONNECTING) && 
		    (rfcomm_con_list[i].initiator == TRUE)) {
			rfcomm = &rfcomm_con_list[i];
			stop = TRUE;
		}
	}
   
	if (rfcomm != NULL) {
		rfcomm->l2cap = l2cap;
		l2cap->upper_con = (void*) rfcomm;

		if (!l2ca_local_conf_done(l2cap))
		{
			/* still haven't sent config request yet */
			
			/* Zero indicates that default values will be used */
			if (l2ca_config_req(l2cap, RFCOMM_MTU, NULL,
					    RFCOMM_FLUSH_TIMEOUT, 0)) {
				D_ERR(FNC"l2ca_config_req failed\n");
			} 
		} else 
			DSYS(FNC"already have sent back a pos response\n");
	} else {
		D_ERR(FNC"couldn't find the correct rfcomm_con object\n");
	}
#undef FNC
}


/* The lower protocol layer, L2CAP, indicates that it has received a
   configuration indication signal and RFCOMM should reply with proper 
   configuration parameters to the L2CAP layer, with a l2cap_config_rsp
   messages and then send a own configuration request messages. */

void 
rfcomm_config_ind(l2cap_con* l2cap)
{
#define FNC "rfcomm_config_ind: "

	/* 
	   FIXME
	   Check whether the received params are acceptable, 
	   accept all for now
	*/

	/* check if we have sent a pos response yet */
	if (!l2ca_remote_conf_done(l2cap)){
		/* still haven't sent a pos configure response*/
		
		if (l2ca_config_rsp(l2cap, l2cap->remote_mtu,NULL,1)) {
			D_ERR(FNC"l2ca_config_rsp failed\n");
		}
	} else 
		DSYS(FNC"already have sent back a pos response\n");


	/* check if we received a pos response on a previous conf req */ 
	if (((rfcomm_con*) l2cap->upper_con)->initiator == FALSE) {

		/* check if we received a pos response on a 
		   previous config req */ 
		if (!l2ca_local_conf_done(l2cap))
		{
			DSYS(FNC"Setting local l2cap mtu to %d\n", 
			      l2cap->local_mtu);
			l2cap->local_mtu=l2cap->remote_mtu;

			if (l2ca_config_req(l2cap, RFCOMM_MTU, NULL,
					    RFCOMM_FLUSH_TIMEOUT,0)) {
				D_ERR(FNC"l2ca_config_req failed\n");
			}
		} else 
			DSYS(FNC"already ready with config req\n");

	} 
#undef FNC
}

/* The lower protocol layer, L2CAP, indicates that the configuration
   procedure has succeed. */

void 
rfcomm_config_cfm(l2cap_con *l2cap, s32 status)
{
#define FNC "rfcomm_config_cfm: "
	D_SND(FNC"\n");
	if (status) {
		DSYS(FNC"configuration failed\n");
	} else {
		rfcomm_con *rf;
		rf = (rfcomm_con *) l2cap->upper_con;
		
		DSYS(FNC"l2cap is now open\n");
		
		if (rf->initiator && 
		    rf->dlci[0].state == CONNECTING) {
			DSYS("sending sabm...finally\n");
			send_sabm(rf, 0);
		}
		else if (!rf->initiator && 
                         ((l2cap->remote_mtu-5) < DEF_RFCOMM_MTU) )
                {

                  /* FIXME - static line = 0 ... */

                  int j;
                  DSYS(FNC"Setting RFCOMM MTU to %d\n", l2cap->remote_mtu-5);
                  for (j = 0; j < 62; j++) {
                    rfcomm_con_list[0].dlci[j].mtu = (l2cap->remote_mtu-5);
                  }
                  
                }
        }
        
#undef FNC
}

/* The lower protocol layer, L2CAP, indicates that the lower layer 
   connection is disconnected. */

void 
rfcomm_disconnect_ind(l2cap_con *l2cap)
{
#define FNC "rfcomm_disconnect_ind: "
	rfcomm_con *rfcomm;
	s32 i;
	D_CTRL(FNC"RFCOMM disconnecting\n");

	rfcomm = ((rfcomm_con*) l2cap->upper_con);

	if (l2ca_disconnect_rsp(l2cap)) {
		D_ERR(FNC"l2ca_disconnect_rsp failed\n");
		return;
	}
  
	for (i = 0; i < 62; i++)
		rfcomm->dlci[i].state = DISCONNECTED;
  
	rfcomm->l2cap = NULL;
	
#ifdef __KERNEL__

	bt_unregister_rfcomm(rfcomm->line);

	/* notify upper tty that this rfcomm connection is down */
	bt_hangupline(rfcomm->line);
#endif

#undef FNC
}

void 
rfcomm_disconnect_cfm(l2cap_con *l2cap)
{
#define FNC "rfcomm_disconnect_cfm: "
	s32 i;
	rfcomm_con *rfcomm;
  
	D_REC(FNC" disconnected\n");

	rfcomm = (rfcomm_con*) l2cap->upper_con;
	rfcomm->l2cap = NULL;
	for (i = 0; i < 62; i++)
		rfcomm->dlci[i].state = DISCONNECTED;

#undef FNC
}

/* This function should be called from the L2CAP layer data should pos32 at
   the beginning of the RFCOMM data, and len should be the length of that 
   data.*/

void 
rfcomm_receive_data(l2cap_con *l2cap, u8 *data, u32 len)
{
#define FNC "rfcomm_receive_data: "
	rfcomm_con *rfcomm;
	short_frame *short_pkt; 
	long_frame *long_pkt;
	u8* uih_data_start;
	u32 uih_len;
	u8 tmp_dlci;

	PRINTPKT("rfcomm_receive_data:",data,len);
	
	D_REC(FNC"%d bytes, our cid is %d\n",len, 
	      l2cap->remote_cid);
	short_pkt = (short_frame*) data;

	tmp_dlci = short_pkt->h.addr.server_chn << 1 | short_pkt->h.addr.d;
	switch (CLR_PF(short_pkt->h.control)) {
	case SABM:
		D_REC(FNC"SABM-packet received\n");
    
		if (crc_check((u8*) short_pkt, LONG_CRC_CHECK, 
			      short_pkt->data[0])) {
			break;
		}

		/* If the SABM command wants to open the control channel, we
		   have to create a new rfcomm_con object */
		if ((tmp_dlci) == 0) {

			D_REC(FNC"server channel == 0\n");
			rfcomm = ((rfcomm_con*) l2cap->upper_con);
      
			D_REC(FNC"setting l2cap_con, no serv.channel yet\n");
			rfcomm->dlci[0].state = CONNECTED;
		}
	
		/* If the channel isn't the control channel, we know that the
		   object exist. If we haven't opened any other channel than
		   the control channel we open the new channel here */

		else if (valid_dlci(tmp_dlci)) {
			rfcomm = ((rfcomm_con*) l2cap->upper_con);

			D_REC(FNC"setting server channel %d\n",
			      short_pkt->h.addr.server_chn);

			/* Don't forget to add the LSB, the d-bit to the open
			   DLCI */
			tmp_dlci = (short_pkt->h.addr.server_chn << 1)
				| (short_pkt->h.addr.d & 1);
			rfcomm->dlci[tmp_dlci].state = CONNECTED;
			
			bt_register_rfcomm(rfcomm, tmp_dlci);
			
#if 0
			/* Here we could send a PN packet for negotiating the
			   frame size, but sice we are the server it's not sure
			   that the oposite side will respond correctly ?!? */

			//Mattias
			/* rfcomm mtu must be less than l2cap mtu due to 
			   rfcomm header size */
			printk("rfcomm (S) trying to negotiate mtu (%d)...\n",
			       l2cap->remote_mtu-5);

			send_pn_msg(rfcomm, 7, (l2cap->remote_mtu-5),
				    tmp_dlci, TRUE);
			rfcomm->dlci[tmp_dlci].state = NEGOTIATING;
#endif
		} else {

			D_REC(FNC"no server on channel %d, sending DM\n",
			      tmp_dlci);
      
			send_dm(((rfcomm_con*) l2cap->upper_con),tmp_dlci);
			D_REC(FNC"sending response on SABM (dm?!)\n");
			break;
		}

		D_REC(FNC"sending back UA\n");
		send_ua((rfcomm_con*) l2cap->upper_con, tmp_dlci);
		break;
    
	case UA:
		D_REC(FNC"UA packet received\n"); 
		rfcomm = ((rfcomm_con*) l2cap->upper_con);
		if (rfcomm->magic != RFCOMM_MAGIC) {
			D_REC(FNC"Invalid magic number\n");
			break;
		}
		if (rfcomm->dlci[0].state == CONNECTING) {
			/* Now we are the initiating side and we have got a
			   respons to our SABM command. We then send a PN
			   messages to negotiat the frame length */
			rfcomm->dlci[0].state = CONNECTED;
			tmp_dlci = ((rfcomm->server_chn << 1) |
				    ((~rfcomm->initiator) & 0x1));
			
			/* must fit in l2cap mtu incl rfcomm hdrs */
			send_pn_msg(rfcomm, 7, rfcomm->dlci[tmp_dlci].mtu,
				    tmp_dlci, TRUE);
			rfcomm->dlci[tmp_dlci].state = NEGOTIATING;

		} else if (rfcomm->dlci[tmp_dlci].state == NEGOTIATING) {
			rfcomm->dlci[tmp_dlci].state = CONNECTED;
		
			bt_register_rfcomm(rfcomm, tmp_dlci);
			D_CTRL(FNC"successfully connected on DLCI:%d\n",
			       tmp_dlci);
			
			/* FIXME: Should we always do this ? */
			rfcomm_msc_msg(rfcomm, EA | RTC | RTR | DV, MCC_CMD,
				       tmp_dlci);
			rfcomm->dlci[tmp_dlci].initiator = TRUE;

			bt_rfcomm_connection_ready(0);
		} else if (rfcomm->dlci[tmp_dlci].state == DISCONNECTING) {
			if (tmp_dlci == 0) {
#ifdef __KERNEL__  
				wake_up_interruptible(&rfcomm_disconnect_wq);
#else
				l2ca_disconnect_req(rfcomm->l2cap);
#endif
        
			} else {
				s32 tmp;
				
				rfcomm->dlci[tmp_dlci].state = DISCONNECTED;
				tmp = get_connected_dlci(rfcomm);
				rfcomm->dlci[tmp].state = DISCONNECTING;
				send_disc(rfcomm, tmp);
			}
		}    
		break;
    
	case DM:
		D_REC(FNC"DM packet received\n");
		break;
    
	case DISC:
		D_REC(FNC"DISC packet received\n");
		if (crc_check(data, LONG_CRC_CHECK, short_pkt->data[0])) {
			break;
		}
		rfcomm = ((rfcomm_con*) l2cap->upper_con);
		/* When the serverchannel is closing the whole connection
		   should be removed */
		if ((short_pkt->h.addr.server_chn) == 0) {
			rfcomm->dlci[0].state = DISCONNECTED;
			/* FIXME:
			   Tell the tty that the link is down */
			send_ua(rfcomm, tmp_dlci);
		} else {
			rfcomm->dlci[tmp_dlci].state = DISCONNECTED;
			send_ua(rfcomm, tmp_dlci);
		}
		D_REC(FNC"DISC, sending back UA\n");
    
		break;
    
	case UIH:
   
		rfcomm = ((rfcomm_con*) l2cap->upper_con);

		if ((short_pkt->h.length.ea) == 0) {
			/* Then we cast the rfcomm packet to a long rfcomm
			   packet */ 
			D_REC(FNC"Long UIH packet received\n");
			long_pkt = (long_frame*) data;
			uih_len = long_pkt->h.length.len;
			uih_data_start = long_pkt->h.data;
			D_REC(FNC"long packet length %d\n",
			      uih_len);
		} else {
			D_REC(FNC"Short UIH pkt received\n");
			uih_len = short_pkt->h.length.len;
			uih_data_start = short_pkt->data;
		}

		if (crc_check(data, SHORT_CRC_CHECK,
			      *(uih_data_start + uih_len))) {
			break;
		}
    
		if (short_pkt->h.addr.server_chn == 0) {
			D_REC(FNC"UIH on serv_channel 0\n");
			process_mcc(data, len, rfcomm,
				    !(short_pkt->h.length.ea));
		} else {
			bt_receive_top(l2cap->upper_con, uih_data_start,
				       uih_len);
		}
		break;
    
	default:
		D_REC(FNC"illegal packet\n");
		break;
	}
#undef FNC
}


/* Copies the tty data into the stack and creates headers and FCS, then the
   packet is sent to the lower layer L2CAP. The packet must not be larger
   than the actual MTU for the L2CAP layer. */

s32 
rfcomm_send_data(u8 *data, u32 count, u8 line, u8 port)
{
#define  FNC "rfcomm_send_data: "
	u32 c;
	u32 total = 0;
	rfcomm_con *rfcomm;
   
	rfcomm = &rfcomm_con_list[line];
	PRINTPKT(FNC,data,count);

	if (rfcomm == NULL) {
		D_ERR(FNC" ERROR rfcomm_con == NULL\n");
		return -1;
	} else if (rfcomm->magic != RFCOMM_MAGIC) {
		D_ERR(FNC"ERROR magic test failed\n");
		return -1;
	} else if(rfcomm->dlci[0].state == FLOW_STOPPED) {
		DSYS(FNC"Flow stopped on all channels, returning zero\n");
		/* FIXME: We need to buffer the incomming data here... */
		return 0;
	} else if (rfcomm->dlci[port].state == FLOW_STOPPED) {
		DSYS(FNC"Flow stopped, returning zero\n");
		/* FIXME: We need to buffer the incomming data here... */
		return 0;
	}
	/* Check whether there are any data channels connected */
	else if (rfcomm->dlci[port].state == CONNECTED) {
		D_SND(FNC"trying to send %d bytes\n", count);
		while (count)
		{
			
			/* As long as there are anything to send we try to send
			   it. We split the data into parts not bigger than the
			   current MTU size. */
			
			c = MIN(count, rfcomm->dlci[port].mtu);
			
			/* FIXME: Optimize c! If we try to send 200 bytes and
			   there are only 150 bytes space in buffer, set c to
			   150 - sizeof(rfcomm_tx_buf)
			*/

			
			
			if ((c=send_uih(data, c, rfcomm, port)) < 0) 
			  return c; /* error */
			else if (c==0)
			  return total; /* sent 0 bytes */
			
			total += c;
			data += c;
			count -= c;
		}
		D_SND(FNC"sent %d bytes\n", total);
		return total;
	}
	else
	{
		D_ERR(FNC"DLCI %d not connected\n", port);
#ifdef __KERNEL__
		/* FIXME - should we return an _error_ if rfcomm isn't up 
		   yet or only tell user process that 0 bytes was written 
		   ??? */
		return 0;
#else
		return -1;
#endif
	}
#undef FNC
}

void 
rfcomm_send_testdata(u32 count, u8 line)
{
	static u8 testdata[1024];
	static s32 testdata_init = 0;
	s32 i;

	DSYS("rfcomm_send_testdata: sending %d bytes\n",count);
	if (!testdata_init) {
		for (i = 0; i < 1024; i++) {
			testdata[i] = (i%25)+ 65;
		}
	} 
	rfcomm_send_data(testdata, count, line, PPP_DLCI);
}

/* Parses a multiplexer control channel packet */

void 
process_mcc(u8* data, u32 len, rfcomm_con *rfcomm, s32 longpkt)
{
#define FNC "process_mcc: "
	mcc_short_frame *mcc_short_pkt;
    
	if (longpkt) {
		mcc_short_pkt = (mcc_short_frame*)(((long_frame*)data)->data);
	} else {
		mcc_short_pkt = (mcc_short_frame*)(((short_frame*)data)->data);
	}
  
	switch (mcc_short_pkt->h.type.type) {
	case TEST:
		if (mcc_short_pkt->h.type.cr == MCC_RSP) {
			D_REC(FNC"Received test command\n");
		} else {
			if ((mcc_short_pkt->h.length.ea) == 0) {
				mcc_long_frame *mcc_long_pkt;
				mcc_long_pkt = (mcc_long_frame*) mcc_short_pkt;
				rfcomm_test_msg(rfcomm, mcc_long_pkt->value,
					      mcc_long_pkt->h.length.len,
					      MCC_RSP);
			} else {
				rfcomm_test_msg(rfcomm, mcc_short_pkt->value, 
					      mcc_short_pkt->h.length.len,
					      MCC_RSP);
			}
		}
		break;
    
	case FCON:  /*Flow control on command*/
		D_REC(FNC"Received Flow control on command\n");
		if (mcc_short_pkt->h.type.cr == MCC_CMD) {
			rfcomm->dlci[0].state = CONNECTED;
			rfcomm_fcon_msg(rfcomm, MCC_RSP);
		}
		break;
    
	case FCOFF:  /*Flow control off command*/
		D_REC(FNC"Received Flow control off command\n");
		if (mcc_short_pkt->h.type.cr == MCC_CMD) {
			rfcomm->dlci[0].state = FLOW_STOPPED;
			rfcomm_fcoff_msg(rfcomm, MCC_RSP);
		}
		break;
    
	case MSC:  /*Modem status command*/
	{
		u8 dlci;
		u8 v24_sigs;
		
		dlci = (mcc_short_pkt->value[0]) >> 2;
		v24_sigs = mcc_short_pkt->value[1];

		if (mcc_short_pkt->h.type.cr == MCC_CMD) {
			D_REC(FNC"Received Modem status command\n");
			if (v24_sigs & 2) {
				D_CTRL(FNC"Device unable to accept frames\n");
				rfcomm->dlci[dlci].state = FLOW_STOPPED;
			} else {
				rfcomm->dlci[dlci].state = CONNECTED;
				D_CTRL(FNC"Flow on on dlci %d\n", dlci);
  			}

			rfcomm_msc_msg(rfcomm, v24_sigs, MCC_RSP, dlci);

			if (!(rfcomm->dlci[dlci].initiated) && !(rfcomm->dlci[dlci].initiator)) {
				rfcomm_msc_msg(rfcomm, EA | RTR | RTC | DV,
					       MCC_CMD, dlci);
				rfcomm->dlci[dlci].initiated = TRUE;
			}
		} else {
			D_REC(FNC"Received Modem status response\n");

			if (v24_sigs & 2) {
				D_CTRL(FNC"Flow stop accepted\n");
			}
		}
		break;
	}
    
	case RPN:  /*Remote port negotiation command*/
	{
		u8 tmp_dlci;

		tmp_dlci = (mcc_short_pkt->value[0]) >> 2;
		
		if (mcc_short_pkt->h.type.cr == MCC_CMD) {
			if (mcc_short_pkt->h.length.len == 1) {
				D_REC(FNC"Received Remote port negotiation command\n");
				rfcomm_rpn_msg(rfcomm, MCC_RSP, tmp_dlci, 0);
			} else {
				/* Accept the other sides settings (accept all
				   for now) */
				D_REC(FNC"Received Remote port negotiation respons\n");
				memcpy(&rpn_val, &mcc_short_pkt->value[1], 8);
				rfcomm_rpn_msg(rfcomm, MCC_RSP, tmp_dlci, 0);
				/* Zero the parametermask after respons */
				memset(&rpn_val.pm, 0, 2);
			}
		}
    
		
		break;
	}
	case RLS: /*Remote line status*/
	{
		u8 tmp_dlci;
		u8 err_code;
			
		D_REC(FNC"Received Remote line status\n");
		if (mcc_short_pkt->h.type.cr == MCC_CMD) {
			tmp_dlci = mcc_short_pkt->value[0] >> 2;
			err_code = mcc_short_pkt->value[1];
		
			rfcomm_rls_msg(rfcomm, MCC_RSP, tmp_dlci, err_code);
		}
		break;
	}
	case PN:  /*DLC parameter negotiation*/
		D_REC(FNC"Received DLC parameter negotiation, PN\n");
		if (longpkt) {
			/* UNPLUGGED Ericsson using 2 bytes length field */
			data++;
		}  
		if (((pn_msg*) data)->mcc_s_head.type.cr == MCC_CMD) {
			u8 tmp_dlci;
			u16 frame_size;
			
			/* If the incoming messages is a command we send
			   back a response */

			tmp_dlci = ((pn_msg*) data)->dlci;
			frame_size = ((pn_msg*) data)->frame_size;

			frame_size = MIN(frame_size, 
					 rfcomm->l2cap->local_mtu -RFCOMM_MAX_HDR_SIZE);
			send_pn_msg(rfcomm, ((pn_msg*) data)->prior, frame_size, tmp_dlci,
				    MCC_RSP);
			rfcomm->dlci[tmp_dlci].mtu = frame_size;
			D_REC(FNC"process_mcc : mtu set to %d\n", 
			       rfcomm->dlci[tmp_dlci].mtu);
			/* FIXME - check that this fits in l2cap mtu */
			

		} else {
			u8 tmp_dlci;
			tmp_dlci = ((pn_msg*) data)->dlci;
			D_REC(FNC"received PN response with:\n");
			D_REC("Frame size:%d\n",((pn_msg*) data)->frame_size);
			rfcomm->dlci[tmp_dlci].mtu  = ((pn_msg*) data)->frame_size;

			D_REC(FNC"process_mcc : mtu set on dlci:%d to %d\n", 
			       tmp_dlci, rfcomm->dlci[tmp_dlci].mtu);

			if (rfcomm->dlci[tmp_dlci].state == NEGOTIATING) {
				send_sabm(rfcomm, tmp_dlci);
			}

		}  
		break;
    
	case NSC: /*Non supported command resonse*/
		D_REC(FNC"Received Non supported command response\n");
		break;
    
	default:  /*Non supported command received*/
		D_REC(FNC"Received a non supported command\n");
    
		send_nsc_msg(rfcomm, mcc_short_pkt->h.type, MCC_RSP);
    
		break;
	}
#undef FNC
}


/* Sending packet functions */

/* Creates a UA packet and puts it at the beginning of the pkt pointer */
                         
s32 
send_ua(rfcomm_con *rfcomm, u8 dlci)
{
	bt_tx_buf *tx_buf;
	short_frame *ua_pkt;
	u32 rfcomm_frame_size;
  
	D_CTRL("send_ua: Creating UA packet to DLCI %d\n",dlci);

	rfcomm_frame_size = sizeof(short_frame) + FCS_SIZE;
	tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + rfcomm_frame_size);
	
	if (!tx_buf) {
		D_ERR("send_ua : didn't get a valid tx_buf\n");
		return -1;
	}
	
	tx_buf->cur_len = rfcomm_frame_size;
  
	ua_pkt = (short_frame*) (tx_buf->data + sizeof(rfcomm_tx_buf));
  
	/* Always one in the address field */
	ua_pkt->h.addr.ea = 1;
	/* If we are the responder the cr bit should be set in a response */
	ua_pkt->h.addr.cr = ((~(rfcomm->initiator)) & 0x1);
	/* The control channel is on DLCI 0, i.e. d-bit should not be set */
	ua_pkt->h.addr.d = (dlci) & 0x1;
	ua_pkt->h.addr.server_chn = (dlci) >> 0x1;
	/* In RFCOMM the F-bit should always be set when sending UA packets */
	ua_pkt->h.control = SET_PF(UA);
	/* The UA packet has length zero, and then the ea bit in the length
	   field should  be set */
	ua_pkt->h.length.ea = 1;
	ua_pkt->h.length.len = 0;
	ua_pkt->data[0] = crc_calc((u8*) ua_pkt, LONG_CRC_CHECK);
  
	return l2cap_send_data(tx_buf,rfcomm->l2cap);
}

/* Creates a DM packet and puts it at the beginning of the pkt pointer */

s32 
send_dm(rfcomm_con *rfcomm, s32 dlci)
{
	bt_tx_buf *tx_buf;
	short_frame *dm_pkt;
	u32 rfcomm_frame_size;
  
	D_CTRL("send_dm: Creating DM packet to DLCI %d\n",dlci);
  
	rfcomm_frame_size = sizeof(short_frame) + FCS_SIZE;
	tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + rfcomm_frame_size);

	if (!tx_buf) {
		D_ERR("send_dm : didn't get a valid tx_buf\n");
		return -1;
	}

	tx_buf->cur_len = rfcomm_frame_size;
  
	dm_pkt = (short_frame*) (tx_buf->data + sizeof(rfcomm_tx_buf));
	/* Always one in the address field */
	dm_pkt->h.addr.ea = 1;
	/* If we are the responder the cr bit should be set in a response */
	dm_pkt->h.addr.cr =  ((~(rfcomm->initiator)) & 0x1);
	/* The control channel is on DLCI 0, i.e. d-bit should not be set */
	dm_pkt->h.addr.d = (dlci) & 0x1;
	dm_pkt->h.addr.server_chn = (dlci) > 1;
	/* In RFCOMM the F-bit should always be set when sending DM packets */
	dm_pkt->h.control = SET_PF(DM);
	/* The DM packet has length zero, and then the ea bit in the length
	   field should  be set */
	dm_pkt->h.length.ea = 1;
	dm_pkt->h.length.len = 0;
	dm_pkt->data[0] = crc_calc((u8*) dm_pkt, LONG_CRC_CHECK);

	return l2cap_send_data(tx_buf,rfcomm->l2cap);
}

s32 
send_sabm(rfcomm_con *rfcomm, u32 dlci)
{
	bt_tx_buf *tx_buf;
	short_frame *sabm_pkt;
	u32 rfcomm_frame_size;

	D_CTRL("send_sabm: Creating SABM packet to DLCI %d\n",dlci);

	rfcomm_frame_size = sizeof(short_frame) + FCS_SIZE;
	tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + rfcomm_frame_size);
	
	if (!tx_buf) {
		D_ERR("send_sabm : didn't get a valid tx_buf\n");
		return -1;
	}

	tx_buf->cur_len = rfcomm_frame_size;
  
	sabm_pkt = (short_frame*) (tx_buf->data + sizeof(rfcomm_tx_buf));
  
	/* Always one in the address field */
	sabm_pkt->h.addr.ea = 1;
	/* If we are the responder the cr bit should be set in a response */
	sabm_pkt->h.addr.cr = ((rfcomm->initiator) & 0x1);
	sabm_pkt->h.addr.d = dlci & 0x1;
	sabm_pkt->h.addr.server_chn = dlci >> 0x1;
	/* In RFCOMM the F-bit should always be set when sending SABM packets
	 */
	sabm_pkt->h.control = SET_PF(SABM);
	/* The SABM packet has length zero, and then the ea bit in the length
	   field should  be set */
	sabm_pkt->h.length.ea = 1;
	sabm_pkt->h.length.len = 0;
	sabm_pkt->data[0] = crc_calc((u8*) sabm_pkt, LONG_CRC_CHECK);
  
	return l2cap_send_data(tx_buf,rfcomm->l2cap);
}

s32 
send_disc(rfcomm_con *rfcomm, u32 dlci)
{
	bt_tx_buf *tx_buf;
	short_frame *disc_pkt;
	u32 rfcomm_frame_size;

	D_CTRL("send_disc: Creating DISC packet to DLCI %d\n",dlci);

	rfcomm_frame_size = sizeof(short_frame) + FCS_SIZE;
	tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + rfcomm_frame_size);

	if (!tx_buf) {
		D_ERR("send_disc : didn't get a valid tx_buf\n");
		return -1;
	}

	tx_buf->cur_len = rfcomm_frame_size;
  
	disc_pkt = (short_frame*) (tx_buf->data + sizeof(rfcomm_tx_buf));
  
	/* Always one in the address field */
	disc_pkt->h.addr.ea = 1;
	/* If we are the responder the cr bit should be set in a response */
	disc_pkt->h.addr.cr = ((rfcomm->initiator) & 0x1);
	disc_pkt->h.addr.d = dlci & 0x1;
	disc_pkt->h.addr.server_chn = dlci >> 0x1;
	/* In RFCOMM the F-bit should always be set when sending DISC packets
	 */
	disc_pkt->h.control = SET_PF(DISC);
	/* The DISC packet has length zero, and then the ea bit in the length
	   field should  be set */
	disc_pkt->h.length.ea = 1;
	disc_pkt->h.length.len = 0;
	disc_pkt->data[0] = crc_calc((u8*) disc_pkt, LONG_CRC_CHECK);
  
	return l2cap_send_data(tx_buf,rfcomm->l2cap);
} 


/* Creates a UIH packet and puts it at the beginning of the pkt pointer
   The funtion returns how many bytes the UIH packet consist of */

s32 
send_uih(u8 *data, u32 len, rfcomm_con *rfcomm, u32 dlci)
{
	bt_tx_buf *tx_buf;
	u32 rfcomm_frame_size;
	
	D_CTRL("send_uih: Creating UIH packet with %d bytes data to DLCI %d\n",
	       len, dlci);

	if (!rfcomm->l2cap->link_up) {
		D_ERR("[RFCOMM]send_uih : could not send data, baseband down\n");
#ifdef __KERNEL__
		return 0;
#else
		return -1; /* FIXME - see comment in rfcomm_send_data */
#endif
	}
	
		
	if (len > SHORT_PAYLOAD_SIZE) {
		long_frame *l_pkt;
    
		rfcomm_frame_size = sizeof(long_frame) + len + FCS_SIZE;

		/* Check for space in buffer, don't forget the size of the
		   L2CAP and HCI headers */
		if (buf_write_room() < (rfcomm_frame_size
					+ sizeof(rfcomm_tx_buf))) {
			return 0;
		}

		tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf)
					  + rfcomm_frame_size);    
		if (!tx_buf) {
			D_ERR("send_uih: didn't get a valid tx_buf\n");
			return -1;
		}
		tx_buf->cur_len = rfcomm_frame_size;
    
		l_pkt = (long_frame*) (tx_buf->data + sizeof(rfcomm_tx_buf));
		set_uih_hdr((void*) l_pkt, dlci, len, rfcomm->initiator);
		memcpy(l_pkt->data, data, len);
		l_pkt->data[len] = crc_calc((u8*) l_pkt, SHORT_CRC_CHECK);
	} else {
		short_frame *s_pkt;

		rfcomm_frame_size = sizeof(short_frame) + len + FCS_SIZE;
		/* Check for space in buffer, don't forget the size of the
		   L2CAP and HCI headers */
		if (buf_write_room() < (rfcomm_frame_size
					+ sizeof(rfcomm_tx_buf))) {
			return 0;
		}
		tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf)
					  + rfcomm_frame_size);
		if (!tx_buf) {
			D_ERR("send_uih: didn't get a valid tx_buf\n");
			return -1;
		}
		tx_buf->cur_len = rfcomm_frame_size;
    
		s_pkt = (short_frame*) (tx_buf->data + sizeof(rfcomm_tx_buf));
		/* Always one */
		set_uih_hdr((void*) s_pkt, dlci, len, rfcomm->initiator);
		memcpy(s_pkt->data, data, len);
		s_pkt->data[len] = crc_calc((u8*) s_pkt, SHORT_CRC_CHECK);
	}

	/* FIXME - How should we propagate result up to higher layers ?
	   through len or success/no success? */
	l2cap_send_data(tx_buf,rfcomm->l2cap);
	return len;
}

/* Sends Multiplexer command packets funktions */

/* Sends a test messages with a specific test pattern. */

s32 
rfcomm_test_msg(rfcomm_con *rfcomm, u8 *test_pattern, u32 len, u8 cr)
{
	bt_tx_buf *tx_buf;
	u32 rfcomm_frame_size;
   
	if (len > SHORT_PAYLOAD_SIZE) {
		long_frame *uih_pkt;
		mcc_long_frame *mcc_pkt;
    
		/* Create long uih packet and long mcc packet */
		rfcomm_frame_size = (sizeof(long_frame)
				     + sizeof(mcc_long_frame) + len +FCS_SIZE);
		tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf)
					  + rfcomm_frame_size);
		if (!tx_buf) {
			D_ERR("rfcomm_test_msg : didn't get a valid tx_buf\n");
			return -1;
		}
		tx_buf->cur_len = rfcomm_frame_size;
		uih_pkt = (long_frame*) (tx_buf->data + sizeof(rfcomm_tx_buf));
    
		set_uih_hdr((short_frame*) uih_pkt, CTRL_CHAN, len + 
			    sizeof(mcc_long_frame), (~rfcomm->initiator)^cr);
		uih_pkt->data[uih_pkt->h.length.len] = crc_calc((u8*) uih_pkt, 
								SHORT_CRC_CHECK);
		mcc_pkt = (mcc_long_frame*) uih_pkt->data;

		/* Always one in the TEST messages */
		mcc_pkt->h.type.ea = EA;
		/* cr tells whether it is a commmand (1) or a response (0) */
		mcc_pkt->h.type.cr = cr;
		mcc_pkt->h.type.type = TEST;
		mcc_pkt->h.length.ea = EA;
		mcc_pkt->h.length.len = len;
		memcpy(mcc_pkt->value,test_pattern,len);
	} else if (len > (SHORT_PAYLOAD_SIZE-sizeof(mcc_short_frame))) {
		long_frame *uih_pkt;
		mcc_short_frame *mcc_pkt;
    
		/* Create long uih packet and short mcc packet */
		rfcomm_frame_size = (sizeof(long_frame)
				     + sizeof(mcc_short_frame) + len+FCS_SIZE);
		tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf)
					  + rfcomm_frame_size);
		if (!tx_buf) {
			D_ERR("rfcomm_test_msg : didn't get a valid tx_buf\n");
			return -1;
		}
		
		tx_buf->cur_len = rfcomm_frame_size;
		uih_pkt = (long_frame*) (tx_buf->data + sizeof(rfcomm_tx_buf));
    
		set_uih_hdr((short_frame*) uih_pkt, CTRL_CHAN, len +
			    sizeof(mcc_short_frame), (~rfcomm->initiator)^cr);
		uih_pkt->data[uih_pkt->h.length.len] = crc_calc((u8*) uih_pkt, 
								SHORT_CRC_CHECK);
		mcc_pkt = (mcc_short_frame*) uih_pkt->data;

		/* Always one in the TEST messages */
		mcc_pkt->h.type.ea = EA;
		/* cr tells whether it is a commmand (1) or a response (0) */
		mcc_pkt->h.type.cr = cr;
		mcc_pkt->h.type.type = TEST;
		mcc_pkt->h.length.ea = EA;
		mcc_pkt->h. length.len = len;
		memcpy(mcc_pkt->value,test_pattern,len);
	} else {
		short_frame *uih_pkt;
		mcc_short_frame *mcc_pkt;

		/* Creat short uih packet and short mcc packet */
		rfcomm_frame_size = (sizeof(short_frame)
				     + sizeof(mcc_short_frame) + len+FCS_SIZE);
		tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf)
					  + rfcomm_frame_size);
		if (!tx_buf) {
			D_ERR("rfcomm_test_msg : didn't get a valid tx_buf\n");
			return -1;
		}
		
		tx_buf->cur_len = rfcomm_frame_size;
    
		uih_pkt = (short_frame*) (tx_buf->data +sizeof(rfcomm_tx_buf));
    
		set_uih_hdr((void*) uih_pkt, CTRL_CHAN, len
			    + sizeof(mcc_short_frame), (~rfcomm->initiator)^cr);
		uih_pkt->data[uih_pkt->h.length.len] = crc_calc((u8*) uih_pkt, 
								SHORT_CRC_CHECK);
		mcc_pkt = (mcc_short_frame*) uih_pkt->data;
    
		/* Always one in the TEST messages */
		mcc_pkt->h.type.ea = EA;
		/* cr tells whether it is a commmand (1) or a response (0) */
		mcc_pkt->h.type.cr = cr;
		mcc_pkt->h.type.type = TEST;
		mcc_pkt->h.length.ea = EA;
		mcc_pkt->h. length.len = len;
		memcpy(mcc_pkt->value,test_pattern,len);
    
	}
	return l2cap_send_data(tx_buf, rfcomm->l2cap);
}

/* Turns on the RFCOMM flow control */

s32 
rfcomm_fcon_msg(rfcomm_con *rfcomm, u8 cr)
{
	bt_tx_buf *tx_buf;
	short_frame *uih_pkt;
	mcc_short_frame *mcc_pkt;
	u32 rfcomm_frame_size;
  
	rfcomm_frame_size = (sizeof(short_frame) + sizeof(mcc_short_frame)
			     + FCS_SIZE);
	tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + rfcomm_frame_size);

	if (!tx_buf) {
		D_ERR("rfcomm_fcon_msg : didn't get a valid tx_buf\n");
		return -1;
	}

	tx_buf->cur_len = rfcomm_frame_size;
  
	uih_pkt = (short_frame*) (tx_buf->data + sizeof(rfcomm_tx_buf));
	set_uih_hdr(uih_pkt, CTRL_CHAN, sizeof(mcc_short_frame),
		    (~rfcomm->initiator)^cr);
	uih_pkt->data[sizeof(mcc_short_frame)] = crc_calc((u8*) uih_pkt, 
							  SHORT_CRC_CHECK);
	mcc_pkt = (mcc_short_frame*) (uih_pkt->data);
  
	mcc_pkt->h.type.ea = EA;
	mcc_pkt->h.type.cr = cr;
	mcc_pkt->h.type.type = FCON;
	mcc_pkt->h.length.ea = EA;
	mcc_pkt->h.length.len = 0;
  
	return l2cap_send_data(tx_buf, rfcomm->l2cap);
}

/* Turns off the RFCOMM flow control */

s32 
rfcomm_fcoff_msg(rfcomm_con *rfcomm, u8 cr)
{
	bt_tx_buf *tx_buf;
	short_frame *uih_pkt;
	mcc_short_frame *mcc_pkt;
	u32 rfcomm_frame_size;
  
	rfcomm_frame_size = (sizeof(short_frame) + sizeof(mcc_short_frame)
			     + FCS_SIZE);
	tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + rfcomm_frame_size);

	if (!tx_buf) {
		D_ERR("rfcomm_fcoff_msg : didn't get a valid tx_buf\n");
		return -1;
	}

	tx_buf->cur_len = rfcomm_frame_size;
  
	uih_pkt = (short_frame*) (tx_buf->data + sizeof(rfcomm_tx_buf));
	set_uih_hdr(uih_pkt, CTRL_CHAN, sizeof(mcc_short_frame),
		    (~rfcomm->initiator)^cr);
	uih_pkt->data[sizeof(mcc_short_frame)] = crc_calc((u8*) uih_pkt, 
							  SHORT_CRC_CHECK);
	mcc_pkt = (mcc_short_frame*) (uih_pkt->data);

	mcc_pkt->h.type.ea = 1;
	mcc_pkt->h.type.cr = cr;
	mcc_pkt->h.type.type = FCOFF;
	mcc_pkt->h.length.ea = 1;
	mcc_pkt->h.length.len = 0;

	return l2cap_send_data(tx_buf, rfcomm->l2cap);
}

s32 rfcomm_rpn_msg(rfcomm_con *rfcomm, u8 cr, u8 dlci, u8 req)
{
	bt_tx_buf *tx_buf;
	rpn_msg* rpn_pkt;
	u32 rfcomm_frame_size;
	u32 rfcomm_payload_size;

	rfcomm_frame_size = sizeof(rpn_msg);

	if (req) {
		rfcomm_frame_size -= sizeof(rpn_values);
	}
	
	rfcomm_payload_size = (rfcomm_frame_size - sizeof(short_frame)
			       - FCS_SIZE);
	
	tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + rfcomm_frame_size);

	if (!tx_buf) {
		D_ERR("rfcomm_rpn_msg : didn't get a valid tx_buf\n");
		return -1;
	}

	tx_buf->cur_len = rfcomm_frame_size;
  
	rpn_pkt = (rpn_msg*) (tx_buf->data + sizeof(rfcomm_tx_buf));
  
	set_uih_hdr((short_frame*) rpn_pkt, CTRL_CHAN, rfcomm_payload_size,
		    (~rfcomm->initiator)^cr);

	rpn_pkt->fcs = crc_calc((u8*) rpn_pkt, SHORT_CRC_CHECK);

	rpn_pkt->mcc_s_head.type.ea = EA;
	rpn_pkt->mcc_s_head.type.cr = cr;
	rpn_pkt->mcc_s_head.type.type = RPN;
	rpn_pkt->mcc_s_head.length.ea = EA;

	rpn_pkt->dlci.ea = EA;
	rpn_pkt->dlci.cr = 1; /* Fixed value */
	rpn_pkt->dlci.d = dlci & 1;
	rpn_pkt->dlci.server_chn = (dlci >> 1);
	
	if (req) {
		rpn_pkt->mcc_s_head.length.len = 1;
		/* Fix, since the packet is ends here when it is a request */
		rpn_pkt->rpn_val.bit_rate = rpn_pkt->fcs;
		return l2cap_send_data(tx_buf, rfcomm->l2cap);
	} else {
		rpn_pkt->mcc_s_head.length.len = 8;
		memcpy(&(rpn_pkt->rpn_val), &rpn_val, sizeof(rpn_values));
		//print_data("",(u8*) rpn_pkt, rfcomm_frame_size);
		return l2cap_send_data(tx_buf, rfcomm->l2cap);
	}
}

s32 
rfcomm_rls_msg(rfcomm_con *rfcomm, u8 cr, u8 dlci, u8 err_code)
{
	bt_tx_buf *tx_buf;
	rls_msg* rls_pkt;
	u32 rfcomm_frame_size;
	u32 rfcomm_payload_size;

	rfcomm_frame_size = sizeof(rls_msg);
	rfcomm_payload_size = rfcomm_frame_size - sizeof(short_frame)-FCS_SIZE;
	tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + rfcomm_frame_size);

	if (!tx_buf) {
		D_ERR("rfcomm_rls_msg : didn't get a valid tx_buf\n");
		return -1;
	}

	tx_buf->cur_len = rfcomm_frame_size;
  
	rls_pkt = (rls_msg*) (tx_buf->data + sizeof(rfcomm_tx_buf));
  
	set_uih_hdr((short_frame*) rls_pkt, CTRL_CHAN, rfcomm_payload_size,
		    (~rfcomm->initiator)^cr);
	rls_pkt->fcs = crc_calc((u8*) rls_pkt, SHORT_CRC_CHECK);
  
	rls_pkt->mcc_s_head.type.ea = EA;
	rls_pkt->mcc_s_head.type.cr = cr;
	rls_pkt->mcc_s_head.type.type = RLS;
	rls_pkt->mcc_s_head.length.ea = EA;
	rls_pkt->mcc_s_head.length.len = 2;
  
	rls_pkt->dlci.ea = EA;
	rls_pkt->dlci.cr = 1; /* Fixed value */
	rls_pkt->dlci.d = dlci & 1;
	rls_pkt->dlci.server_chn = dlci >> 1;
	rls_pkt->error = err_code;
	rls_pkt->res = 0;
  
	return l2cap_send_data(tx_buf, rfcomm->l2cap);
}
/* Sends an PN-messages and sets the not negotiable parameters to their
   default values in RFCOMM */

s32 
send_pn_msg(rfcomm_con *rfcomm, u8 prior, u32 frame_size, u32 dlci, u8 cr)
{
	bt_tx_buf *tx_buf;
	pn_msg *pn_pkt;
	u32 rfcomm_frame_size;
	D_SND("send_pn_msg: DLCI 0x%02x, prior:0x%02x, frame_size:%d, cr:%x\n",
	      dlci, prior, frame_size, cr);

	/* FIXME: Can't use structures here, sizeof doesn't work... */
	rfcomm_frame_size = 14; //sizeof(pn_msg);
	tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + rfcomm_frame_size);

	if (!tx_buf) {
		D_ERR("send_pn_msg : didn't get a valid tx_buf\n");
		return -1;
	}

	tx_buf->cur_len = rfcomm_frame_size;

	pn_pkt = (pn_msg*) (tx_buf->data + sizeof(rfcomm_tx_buf));
	/* Set the UIH headers */
	set_uih_hdr((void*) pn_pkt, CTRL_CHAN, rfcomm_frame_size - 
		    (sizeof(short_frame) + FCS_SIZE), (~rfcomm->initiator)^cr);
	pn_pkt->fcs = crc_calc((u8*) pn_pkt, SHORT_CRC_CHECK);
  
	/* set the MCC-packet header */
	pn_pkt->mcc_s_head.type.ea = 1;
	pn_pkt->mcc_s_head.type.cr = cr;
	pn_pkt->mcc_s_head.type.type = PN;
	pn_pkt->mcc_s_head.length.ea = 1;
	/* The PN packet has a fix length of 8 bytes */
	pn_pkt->mcc_s_head.length.len = 8;

	/* Set the parameters in the PN-packet */
	pn_pkt->res1 = 0;
	pn_pkt->res2 = 0;
	pn_pkt->res3 = 0;
	pn_pkt->dlci = dlci;
	pn_pkt->frame_type = 0;
	pn_pkt->convergence_layer = 0;
	pn_pkt->prior = prior;
	pn_pkt->ack_timer = 0;
	pn_pkt->frame_size = frame_size;
	pn_pkt->max_nbrof_retrans = 0;
	pn_pkt->win_size = 0;
  
	return l2cap_send_data(tx_buf,rfcomm->l2cap);
}

/* Sendares a Not supported command - command, which needs 3 bytes */

s32 
send_nsc_msg(rfcomm_con *rfcomm, mcc_type cmd, u8 cr) 
{
	bt_tx_buf *tx_buf;
	nsc_msg *nsc_pkt;
	u32 rfcomm_frame_size;
  
	rfcomm_frame_size = sizeof(nsc_msg) + FCS_SIZE;
	tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + rfcomm_frame_size);

	if (!tx_buf) {
		D_ERR("send_nsc_msg : didn't get a valid tx_buf\n");
		return -1;
	}

	tx_buf->cur_len = rfcomm_frame_size;
	
	nsc_pkt = (nsc_msg*) (tx_buf->data + sizeof(rfcomm_tx_buf));
 
	set_uih_hdr((void*) nsc_pkt, CTRL_CHAN, sizeof(nsc_msg)
		    - sizeof(short_frame), (~rfcomm->initiator)^cr);

	nsc_pkt->fcs = crc_calc((u8*) nsc_pkt, SHORT_CRC_CHECK);

	nsc_pkt->mcc_s_head.type.ea = 1;
	nsc_pkt->mcc_s_head.type.cr = cr;
	nsc_pkt->mcc_s_head.type.type = NSC;
	nsc_pkt->mcc_s_head.length.ea = 1;
	nsc_pkt->mcc_s_head.length.len = 1;

	nsc_pkt->command_type.ea = 1;
	nsc_pkt->command_type.cr = cmd.cr;
	nsc_pkt->command_type.type = cmd.type;

	return l2cap_send_data(tx_buf, rfcomm->l2cap);
}

s32 rfcomm_msc_msg(rfcomm_con *rfcomm, u8 value, u8 cr, u8 dlci)
{
	bt_tx_buf *tx_buf;
	msc_msg *msc_pkt;
	u32 rfcomm_frame_size;
  
	rfcomm_frame_size = sizeof(msc_msg);
	tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + rfcomm_frame_size);

	if (!tx_buf) {
		D_ERR("send_nsc_msg : didn't get a valid tx_buf\n");
		return -1;
	}

	tx_buf->cur_len = rfcomm_frame_size;

	msc_pkt = (msc_msg*) (tx_buf->data + sizeof(rfcomm_tx_buf));
 
	set_uih_hdr((void*) msc_pkt, CTRL_CHAN, sizeof(msc_msg)
		    - sizeof(short_frame) - FCS_SIZE, (~rfcomm->initiator)^cr);

	msc_pkt->fcs = crc_calc((u8*) msc_pkt, SHORT_CRC_CHECK);

	msc_pkt->mcc_s_head.type.ea = 1;
	msc_pkt->mcc_s_head.type.cr = cr;
	msc_pkt->mcc_s_head.type.type = MSC;
	msc_pkt->mcc_s_head.length.ea = 1;
	msc_pkt->mcc_s_head.length.len = 2;

	msc_pkt->dlci.ea = 1;
	msc_pkt->dlci.cr = 1;
	msc_pkt->dlci.d = dlci & 1;
	msc_pkt->dlci.server_chn = (dlci >> 1) & 0x1f;

	msc_pkt->v24_sigs = value;
	return l2cap_send_data(tx_buf, rfcomm->l2cap);
}


void
set_uih_hdr(short_frame *uih_pkt, u8 dlci, u32 len, u8 cr)
{
	uih_pkt->h.addr.ea = 1;
	uih_pkt->h.addr.cr = cr;
	uih_pkt->h.addr.d = dlci & 0x1;
	uih_pkt->h.addr.server_chn = dlci >> 1;
	uih_pkt->h.control = CLR_PF(UIH);
  
	if (len > SHORT_PAYLOAD_SIZE) {
		((long_frame*) uih_pkt)->h.length.ea = 0;
		((long_frame*) uih_pkt)->h.length.len = len;  
	} else {
		uih_pkt->h.length.ea = 1;
		uih_pkt->h.length.len = len;  
	}

}

rfcomm_con* 
get_new_rfcomm_con(void)
{
	s32 i = 0;

	while ((i<MAX_NBR_OF_TTY)
	       && (rfcomm_con_list[i].dlci[0].state != DISCONNECTED)) {
		i++;
	}
	D_CTRL("get_new_rfcomm_con: rfcomm_con -> tty%d\n",i);
	if (rfcomm_con_list[i].dlci[0].state != DISCONNECTED) {
		return NULL;
	} else {
		/* Reset these parameters just incase... */
		rfcomm_con_list[i].l2cap = NULL;
		return &rfcomm_con_list[i];
	}
}

rfcomm_con* 
get_rfcomm_con(u8 line)
{
	return &rfcomm_con_list[line];
}

s32 
valid_dlci(u8 dlci)
{
	if ((dlci < 62) && (dlci > 1)) {
		return TRUE;
	} else {
		return FALSE;
	}
}

s32 get_connected_dlci(rfcomm_con *rfcomm)
{
	s32 tmp;

	tmp = 61;
	while ((rfcomm->dlci[tmp].state == DISCONNECTED) && (tmp > 0)) {
		tmp -= 1;
	}

	return tmp;
}

/* Functions for the crc-check and calculation */

#define CRC_VALID 0xcf

/* This functions check whether the checksum is correct or not. Length is
   the number of bytes in the message, data points to the beginning of the
   message */

u32 
crc_check(u8 *data, u32 length, u8 check_sum)
{
	u8 fcs = 0xff;

	PRINTPKT("crc_check:",data,length);
	while (length--) {
		fcs = crctable[fcs^*data++];
	}
	fcs = crctable[fcs^check_sum];

	if (fcs == (uint) 0xcf)/*CRC_VALID)*/{
		D_REC("crc_check: CRC check OK\n");
		return 0;
	} else {
		D_ERR("crc_check: CRC check failed\n");
		return 1;
	}
}

/* Calculates the checksum according to the RFCOMM specification */

u8 
crc_calc(u8 *data, u32 length)
{
	u8 fcs = 0xff;
  
	while (length--) {
		fcs = crctable[fcs^*data++];
	}
  
	/*Ones complement*/
	return 0xff-fcs;
}

/* Calulates a reversed CRC table for the FCS check */

void
create_crctable(u8 table[])
{
	s32 i,j;
  
	u8 data;
	u8 code_word = (u8) 0xe0;  /*pol = x8+x2+x1+1*/
	u8 sr = (u8) 0;            /*Shiftregister initiated to zero*/

	for (j = 0; j < 256; j++) {
		data = (u8) j;
    
		for (i = 0; i < 8; i++) {
			if ((data & 0x1)^(sr & 0x1)) {
				sr >>= 1;
				sr ^= code_word;
			} else {
				sr >>= 1;
			}
      
			data >>= 1;
			sr &= 0xff;
		}
    
		table[j] = sr;
		sr = 0;
	} 
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/

/* /proc file functions */

const char * STATE2NAME[]={
	"DISCONNECTED", 
	"CONNECTING",
	"NEGOTIATING",
	"CONNECTED",
	"DISCONNECTING",
};

s32 rfcomm_sprint_con(u8 *buf)
{
	s32 i, j;
	s32 len=0;

	for (i = 0; i < MAX_NBR_OF_TTY; i++) {

		/* FIXME - move mtu etc into each dlci port, 
		   should not be in 'line' struct */
		
		for (j = 0; j < 62; j++){	
			if (rfcomm_con_list[i].dlci[j].state != DISCONNECTED){
				
				len+=sprintf(buf+len, "line[%d] mtu[%d] ",
					     rfcomm_con_list[i].line, 
					     rfcomm_con_list[i].dlci[j].mtu);
				
				len+=sprintf(buf+len, "dlci#%d state[%s]\n", 
					     j, STATE2NAME[rfcomm_con_list[i].dlci[j].state]);
			}
		}
	}
	return len;
}


s32 rfcomm_sprint_status(u8 *buf)
{
	s32 len=0;
	len+=sprintf(buf+len, "\n[RFCOMM]\n\n");
	len+=rfcomm_sprint_con(buf+len);
	return len;
}



/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
