/* 
 * test.c -- Test layer used to verify stack       
 *
 * Copyright (C) 2000  Axis Communications AB
 *
 * 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: test.c,v 1.9 2000/10/26 14:42:38 mattias Exp $x
 *
 */

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

#ifdef __KERNEL__
#include <linux/malloc.h>
#include <linux/bluetooth/test.h>
#include <linux/bluetooth/btcommon.h>
#include <linux/bluetooth/btmem.h>
#include <linux/bluetooth/l2cap.h>
#else
#include <string.h>

#include "include/test.h"
#include "include/btcommon.h"
#include "include/btdebug.h"
#include "include/btmem.h"
#include "include/l2cap.h"
#endif

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

#define TEST_DBG_STR "          TEST "

#define TEST_DEBUG_STATE 1
#define TEST_DEBUG_CON 1
#define TEST_DEBUG_RCV 1
#define TEST_DEBUG_XMIT 1
#define TEST_DEBUG_MISC 1
#define TEST_DEBUG_DATA 0

#if TEST_DEBUG_STATE
/* State machine */
#define D_STATE(fmt...) printk(TEST_DBG_STR fmt)
#define PRINTSTATE(con) (printk("Current state : %s\n",\
                         state_name[con->current_state]))
#else
/* State machine */
#define D_STATE(fmt)
#define PRINTSTATE(con)
#endif

#if TEST_DEBUG_RCV
/* Receive data */
#define D_RCV(fmt...) printk(TEST_DBG_STR fmt)
#else
#define D_RCV(fmt...)
#endif

#if TEST_DEBUG_XMIT
/* Send data */
#define D_XMIT(fmt...) printk(TEST_DBG_STR fmt)
#else
#define D_XMIT(fmt...)
#endif

#if TEST_DEBUG_MISC
/* Misc */
#define D_MISC(fmt...) printk(TEST_DBG_STR fmt)
#else
#define D_MISC(fmt...)
#endif

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

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

/****************** TYPE DEFINITION SECTION *********************************/

l2cap_con *testcon;

void test_init(void)
{
	protocol_layer this_layer;

	DSYS("Initialising TEST\n");
  
	/* Set the confirm and indication functions for the L2CAP-layer */
	this_layer.con_ind = test_connect_ind;
	this_layer.conf_ind = test_config_ind;
	this_layer.disc_ind = test_disconnect_ind;

	this_layer.con_cfm = test_connect_cfm;
	this_layer.conf_cfm = test_config_cfm;
	this_layer.disc_cfm = test_disconnect_cfm;

	this_layer.receive_data = test_receive_data;

	l2cap_register_upper(L2CAP_TEST_LAYER, &this_layer);
}

void test_shutdown(void)
{
	DSYS("Shutting down TST\n");
}

s32
test_connect_req(BD_ADDR bd)
{
	D_STATE("test_connect_req to psm 0x%x\n", L2CAP_TEST_LAYER);

	if (l2ca_connect_req(bd, L2CAP_TEST_LAYER)) {
		D_ERR(" tcs_connect_req: l2ca_connect_req failed\n");
		return -1; 
	}
	return 0;
}

s32
test_connect_psmreq(BD_ADDR bd, u16 psm)
{
	D_STATE("test_connect_req on psm 0x%x\n", psm);

	if (l2ca_connect_req(bd, psm)) {
		D_ERR(" tcs_connect_req: l2ca_connect_req failed\n");
		return -1; 
	}
	return 0;
}

void test_connect_ind(l2cap_con *l2cap) 
{
	D_STATE("test_connect_ind : remote cid : %d\n", l2cap->remote_cid);
	
	if(l2ca_connect_rsp(l2cap, RES_SUCCESS, STAT_NOINFO)) {
		D_ERR("test_connect_ind: l2ca_connect_rsp failed\n"); 
		return;
	}

	/* (temp fix for test interface) store connection */
	testcon=l2cap;
}

/* only client receives connect cfm */
void test_connect_cfm(l2cap_con *l2cap, int status)
{
	D_STATE("test_connect_cfm\n");
	
	if ( !l2ca_local_conf_done(l2cap) )
	{
		/* still haven't sent config request yet */
		if(l2ca_config_req(l2cap, TEST_MTU, NULL, 
				   TEST_FLUSH_TIMEOUT, 0)){
			D_ERR("test_config_cfm : Configuration request failed\n");
		}
		/* store connection */
		testcon=l2cap;

	} else 	       
		D_RCV("test_config_cfm : already have sent config request\n");
}

/* someone wants to configure l2cap... */
void 
test_config_ind(l2cap_con* l2cap)
{ 
	D_STATE("test_config_ind : remote cid : %d remote_mtu : %d\n", 
		l2cap->remote_cid, l2cap->remote_mtu);
	
	/* 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 /* ok */)){
			D_ERR("test_config_ind : Configuration response failed\n");
		}    
	} else 
		printk("test_config_ind : already have sent back a pos response\n");

	/* check if we received a pos response on a previous config req */ 
	if (!l2ca_local_conf_done(l2cap))
	{
		D_RCV("Setting local mtu to %d on con (%d:%d)\n", 
		     l2cap->local_mtu, l2cap->local_cid, l2cap->remote_cid);

		/* up3 -- fixme, use real options not static values */

		/* remote options is set in l2cap layer and contains values 
		   for the config req (parse_options) */
 		if(l2ca_config_req(l2cap, l2cap->remote_mtu, NULL, 0xffff, 0))
			D_ERR("test_config_ind : configuration request failed\n");
	} else 
		D_RCV("already ready with config req\n");
}

void test_config_cfm(l2cap_con *l2cap, int status)
{
	D_STATE("test_config_cfm : remote cid : %d\n", l2cap->remote_cid);
	
	D_STATE("Now we have an open l2cap channel\n");

	/* negotiate upper protocol */
}

void test_disconnect_ind(l2cap_con *l2cap) 
{
	D_STATE("test_disconnect_ind : (%d:%d)\n", 
		l2cap->local_cid, l2cap->remote_cid);

	l2ca_disconnect_rsp(l2cap);
}

void test_disconnect_cfm(l2cap_con *l2cap)
{
	D_STATE("TEST_disconnect_cfm: remote cid : %d\n", l2cap->remote_cid);
}

s32 test_disconnect_req(l2cap_con *con)
{
	if (!con)
		return -1;
	
	D_STATE("test_disconnect_req\n");
	return l2ca_disconnect_req(con);
}

void test_receive_data(l2cap_con *l2cap, unsigned char* data, u32 len)
{
	PRINTPKT("test_receive_data : ", data, len);  
}

s32 test_send_data(l2cap_con *con, u8 *testdata, s32 len)
{
	bt_tx_buf *tx_buf;

	printk("test_send_data : sending %d bytes\n", len);
	
	if (!con)
	  return -1;

	/* tx bufs are all the same for each upper layer ... FIX one common */
	tx_buf = subscribe_bt_buf(sizeof(rfcomm_tx_buf) + len);

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

	tx_buf->cur_len = len;

	memcpy(tx_buf->data+sizeof(rfcomm_tx_buf), testdata, len);

	return l2cap_send_data(tx_buf, con);
}

/****************** END OF FILE sdp.c ***************************************/
