blob: 157fa2414767b85a04b0aec2f6f8b7e67ebdb551 [file] [log] [blame]
/*
* Common Functionality for pipe
*
* Broadcom Proprietary and Confidential. Copyright (C) 2017,
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
* the contents of this file may not be disclosed to third parties, copied
* or duplicated in any form, in whole or in part, without the prior
* written permission of Broadcom.
*
*
* <<Broadcom-WL-IPTag/Proprietary:>>
*
* $Id: wlu_pipe.c 625881 2016-03-18 02:58:34Z $
*/
#ifdef WIN32
#define NEED_IR_TYPES
#include <windows.h>
#include <epictrl.h>
#include <irelay.h>
#endif /* WIN32 */
#ifdef LINUX
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <wlioctl.h>
#include <net/if.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#if defined(TARGETOS_symbian)
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#else
#if !defined(TARGETOS_nucleus) && !defined(__FreeBSD__)
#include <malloc.h>
#endif
#endif /* TARGETOS_symbian */
#include <typedefs.h>
#include <wlioctl.h>
#include <proto/ethernet.h>
#include <bcmendian.h>
#include <bcmutils.h>
#include <bcmcdc.h>
#include <proto/802.11.h>
#if defined(RWL_WIFI) || defined(WIFI_REFLECTOR)
#include <rwl_wifi.h>
#endif /* defined(RWL_WIFI) || defined(WIFI_REFLECTOR) */
#include "wlu.h"
#include "wlu_remote.h"
#ifdef DHD_VISTA
#include "wlu_remote_vista.h"
#endif /* DHD_VISTA */
static rem_ioctl_t rem_cdc;
char *g_rwl_device_name_serial = "";
int g_rwl_device_baud = 115200;
bool g_rwl_swap = FALSE;
char g_rem_ifname[IFNAMSIZ] = "\0";
int need_speedy_response; /* Indicate findserver is checking channels */
#ifdef LINUX
/* Linux 100 usec */
#define SYNC_TIME 100
#else
/* WinXP 1 sec */
#define SYNC_TIME 1
#endif
#define UART_FIFO_LEN 64
#define END_OF_PACK_SEP_LEN 2
#define INIT_CMD_SLEEP 500
#define dtoh32(i) i
/* dword align allocation */
union {
uchar bufdata[ETHER_ADDR_LEN];
uint32 alignme;
} bufmac_wlu;
char *g_rwl_buf_mac = (char*) &bufmac_wlu.bufdata;
#ifdef RWL_WIFI
/* dword align allocation */
union {
uchar shelldata[WL_MAX_BUF_LEN];
uint32 alignme;
} shell_wlu;
char *g_rwl_buf_shell = (char*) &shell_wlu.shelldata;
int rwl_find_remote_wifi_server(void *wl, char *id);
int wl_ioctl(void *wl, int cmd, void *buf, int len, bool set);
#ifdef DHD_VISTA
extern GUID dev;
#endif
/*
* This function runs a set of commands before running the wi-fi server
* This is avoids packet drops and improves performance.
* We run the following wl commands
* up, mpc 0, wsec 0, slow_timer 999999, fast_timer 999999, glacial_timer 999999
* legacylink 1, monitor 1.
*/
void remote_wifi_ser_init_cmds(void *wl)
{
int err;
char bigbuf[RWL_WIFI_BUF_LEN];
uint len = 0, count;
/* The array stores command, length and then data format */
remote_wifi_cmds_t wifi_cmds[] = {
{WLC_UP, NULL, 0x0},
{WLC_SET_VAR, "mpc", 0},
{WLC_SET_WSEC, NULL, 0x0},
{WLC_SET_VAR, "slow_timer", 999999},
{WLC_SET_VAR, "fast_timer", 999999},
{WLC_SET_VAR, "glacial_timer", 999999},
{WLC_SET_MONITOR, NULL, 0x1},
{WLC_SET_PM, NULL, 0x0}
};
for (count = 0; count < ARRAYSIZE(wifi_cmds); count++) {
if (wifi_cmds[count].data == NULL)
len = sizeof(int);
else
len = (uint)strlen(wifi_cmds[count].data) + 1 + sizeof(int);
/* If the command length exceeds the buffer length continue
* executing the next command
*/
if (len > sizeof(bigbuf)) {
DPRINT_ERR(ERR, "Err: command len exceeds buf len. Check"
"initialization cmds\n");
continue;
}
if (wifi_cmds[count].data != NULL) {
strcpy(bigbuf, wifi_cmds[count].data);
memcpy(&bigbuf[strlen(wifi_cmds[count].data)+1],
(char*)&wifi_cmds[count].value, sizeof(int));
} else {
memcpy(&bigbuf[0], (char*)&wifi_cmds[count].value, sizeof(int));
}
#ifdef WIN32
/* Add OID base for NDIS commands */
#ifdef DHD_VISTA
err = (int)ir_vista_setinformation(wl, &dev, wifi_cmds[count].cmd + WL_OID_BASE,
bigbuf, &len);
#else
err = (int)ir_setinformation(wl, wifi_cmds[count].cmd + WL_OID_BASE, bigbuf, &len);
#endif
#endif /* DHD_VISTA */
#if defined(LINUX) || defined(TARGETOS_symbian)
if (wifi_cmds[count].cmd == WLC_UP)
/* NULL needs to be passed to the driver if WL UP command needs to
* be executed Otherwise driver hangs
*/
err = wl_ioctl(wl, wifi_cmds[count].cmd,
NULL, 0, TRUE);
else
err = wl_ioctl(wl, wifi_cmds[count].cmd,
(void*)&bigbuf, len, TRUE);
#endif
rwl_sleep(INIT_CMD_SLEEP);
}
BCM_REFERENCE(err);
}
/* When user wants to execute local CMD being in remote wifi mode, this fucntion is used
* to change the remote types.
* This fucntion is called to swap the remote type to execute the cmd using the local
* driver interface.
* This is required for to call proper front end fucntions to achive the local set/get ioctl.
*/
void
rwl_wifi_swap_remote_type(int flag)
{
static int remote_flag;
if (flag == REMOTE_WIFI) {
remote_type = NO_REMOTE;
remote_flag = flag;
} else if (remote_flag == REMOTE_WIFI) {
remote_type = remote_flag;
remote_flag = flag;
}
return;
}
void
rwl_wifi_free_list(dot11_action_wifi_vendor_specific_t *list[])
{
int i;
for (i = 0; i < RWL_DEFAULT_WIFI_FRAG_COUNT; i++) {
if (list[i])
free(list[i]);
}
}
/*
* Configures local channel for finding server.
* Server call this fucntion for getting its current channel,
* client uses this fucntion for setting its channel to new channel.
*/
static int
rwl_wifi_config_channel(void *wl, int cmd, int *channel)
{
int error;
channel_info_t ci;
error = -1;
/* Get functionality is used only by server */
if (cmd == WLC_GET_CHANNEL) {
memset((char*)&ci, 0, sizeof(ci));
if ((error = wl_get(wl, cmd, &ci, sizeof(channel_info_t))) < 0)
return error;
ci.hw_channel = dtoh32(ci.hw_channel);
ci.scan_channel = dtoh32(ci.scan_channel);
ci.target_channel = dtoh32(ci.target_channel);
if (ci.scan_channel) {
printf("Scan in progress.\n");
}
*channel = ci.hw_channel;
}
if (cmd == WLC_SET_CHANNEL) {
/* Set functionality is used by the client */
ci.target_channel = *channel;
/* When user wants to execute local CMD being in remote wifi mode,
* rwl_wifi_swap_remote_type fucntion is used to change the remote types.
*/
rwl_wifi_swap_remote_type(remote_type);
error = wl_set(wl, cmd, &ci.target_channel, sizeof(int));
/* rever it back to same old remote type */
rwl_wifi_swap_remote_type(remote_type);
}
return error;
}
/*
allocate the memory for action frame and update with wifi tranport header.
*/
dot11_action_wifi_vendor_specific_t *
rwl_wifi_allocate_actionframe()
{
dot11_action_wifi_vendor_specific_t *action_frame;
if ((action_frame = (dot11_action_wifi_vendor_specific_t *)
malloc(RWL_WIFI_ACTION_FRAME_SIZE)) == NULL) {
DPRINT_ERR(ERR, "rwl_wifi_allocate_actionframe: unable to allocate frame \n");
return action_frame;
}
action_frame->category = RWL_ACTION_WIFI_CATEGORY;
action_frame->OUI[0] = RWL_WIFI_OUI_BYTE0;
action_frame->OUI[1] = RWL_WIFI_OUI_BYTE1;
action_frame->OUI[2] = RWL_WIFI_OUI_BYTE2;
action_frame->type = RWL_WIFI_DEFAULT_TYPE;
action_frame->subtype = RWL_WIFI_DEFAULT_SUBTYPE;
return action_frame;
}
/*
* Send the valid action frame (CDC+DATA) through the REF driver interface.
* if the CMD is "findserver" then "findmypeer" frames are sent on the diffrent
* channels to reconnect
* to with server. Other wl cmd takes the normal path.
* parameter 3 , i.e. buf contains the cmd line arguments and buf_len is the actual
* length of the buf. data_len is the length of the actual data to be sent to remote server.
*/
int
remote_CDC_wifi_tx(void *wl, uint cmd, uchar *buf, uint buf_len, uint data_len, uint flags)
{
rem_ioctl_t *rem_ptr = &rem_cdc;
int error, read_try;
dot11_action_wifi_vendor_specific_t *rem_wifi_send;
/* prepare CDC header */
rem_ptr->msg.cmd = cmd;
rem_ptr->msg.len = buf_len;
rem_ptr->msg.flags = flags;
rem_ptr->data_len = data_len;
if (strlen(g_rem_ifname) != 0)
strncpy(rem_ptr->intf_name, g_rem_ifname, (int)IFNAMSIZ);
rwl_swap_header(rem_ptr, HOST_TO_NETWORK);
if ((data_len > buf_len)) {
DPRINT_ERR(ERR, "remote_CDC_wifi_tx: data_len (%d) > buf_len (%d)\n",
data_len, buf_len);
return (FAIL);
}
/* client will not send data greater than RWL_WIFI_FRAG_DATA_SIZE to server,
* this condition should not be hit on client side, when sending the cmd
* to remote server
*/
if (data_len > RWL_WIFI_FRAG_DATA_SIZE)
DPRINT_DBG(OUTPUT, "data size exceeds data_len %d\n", rem_ptr->msg.len);
if ((buf != NULL) && (strlen((char*)buf) >= (sizeof(RWL_WIFI_FIND_SER_CMD)-1)) &&
(!strcmp((char*)buf, RWL_WIFI_FIND_SER_CMD))) {
/* This is special case for wifi, when user wants to findserver,
* client has to execute it locally.Find the channel on the on
* which DUT is operating and sync up with specified MAC address,
* retry if fails to find the server
*/
for (read_try = 0; read_try < RWL_WIFI_RETRY; read_try++) {
if (((error = rwl_find_remote_wifi_server(wl,
&g_rwl_buf_mac[0])) == 0)) {
break;
}
}
return error;
}
if ((rem_wifi_send = rwl_wifi_allocate_actionframe()) == NULL) {
DPRINT_ERR(ERR, "remote_CDC_wifi_tx: Failed to allocate memory\n");
return (FAIL);
}
/* only data length needs to be sent to remote server using this function
* This function is only meant for client to send data to server
* Copy the CDC header and data to action frame data feild
* Now we have encapsulated the CDC header and data completely to in the
* action frame.
*/
memcpy((void*)&rem_wifi_send->data[RWL_WIFI_CDC_HEADER_OFFSET],
(char*)rem_ptr, REMOTE_SIZE);
if (buf != NULL) {
memcpy((void*)&rem_wifi_send->data[REMOTE_SIZE], buf, data_len);
}
/* Send the action frame to remote server using the rwl_var_setbuf fucntion,
* which will use the local driver interface to send this frame on the air
*/
if ((error = rwl_var_send_vs_actionframe(wl, RWL_WIFI_ACTION_CMD, rem_wifi_send,
RWL_WIFI_ACTION_FRAME_SIZE)) < 0) {
DPRINT_ERR(ERR, "Unable to read the action frame %d error\n", error);
}
free(rem_wifi_send);
return error;
}
/*
* Read the valid action frame through the REF/DUT driver interface.
* Retry for no of times, wait for action frame for the specified time.
*/
int
remote_CDC_DATA_wifi_rx(void *wl, dot11_action_wifi_vendor_specific_t * rec_frame)
{
int error, read_try;
void *ptr = NULL;
/* retry is to ensure to read late arrival action frame */
for (read_try = 0; read_try < RWL_WIFI_RX_RETRY; read_try++) {
/* read the action frame queued in the local driver wifi queue */
if ((error = rwl_var_getbuf(wl, RWL_WIFI_GET_ACTION_CMD, rec_frame,
RWL_WIFI_ACTION_FRAME_SIZE, &ptr)) < 0) {
DPRINT_ERR(ERR, "remote_CDC_DATA_wifi_rx: Error in reading the frame %d\n",
error);
return error;
}
/* copy the read action frame to the user frame and cjheck for the action category.
* If the action category matches with RWL_ACTION_WIFI_CATEGORY ,
* then its the valid frame, otherwise ignore it.
*/
memcpy((char*)rec_frame, ptr, RWL_WIFI_ACTION_FRAME_SIZE);
if (rec_frame->category == RWL_ACTION_WIFI_CATEGORY) {
break;
} else {
/* If we are executing findserver then sleep less */
if (!need_speedy_response)
rwl_sleep(RWL_WIFI_RX_DELAY);
else
rwl_sleep(RWL_CHANNEL_RX_SCAN_DELAY);
}
}
/* If failed to get the valid frame , indicate the error */
if (!(rec_frame->category == RWL_ACTION_WIFI_CATEGORY)) {
return (FAIL);
}
return error;
}
/*
* read data that has reached client in fragments. If the functtion is
* called from rwl_shell_information_fe then the flag will be set to 1.
* For shell response this function will output the response on the standard interface.
* Response will be coming in out of order , this fucntion will make it inorder.
* Duplicate action frames are ignored.
*/
int
remote_CDC_DATA_wifi_rx_frag(void *wl, rem_ioctl_t *rem_ptr, uint input_len,
void *input, bool shell)
{
int error, totalfrag, seq_num, num_frags, remainingbytes;
dot11_action_wifi_vendor_specific_t *rec_frame;
uchar *input_buf = (uchar*)input;
/* An array of pointers to each recieved frag */
dot11_action_wifi_vendor_specific_t *master_list[RWL_DEFAULT_WIFI_FRAG_COUNT];
UNUSED_PARAMETER(input_len);
remainingbytes = 0;
memset(master_list, 0, sizeof(master_list));
/* in case of shell cmd's receive size is unknown */
if (shell) {
input_buf = (uchar*)g_rwl_buf_shell;
memset(input_buf, 0, WL_MAX_BUF_LEN);
}
/* We don't yet know how many fragments we will need to read since the
length is contained in the first frgment of the message itself. Set
totalfrag to an arbitry large number and we will readjust it after we
successfully recieve the first frag.
*/
totalfrag = RWL_DEFAULT_WIFI_FRAG_COUNT;
for (num_frags = 0; num_frags <= totalfrag; num_frags++) {
if ((rec_frame = rwl_wifi_allocate_actionframe()) == NULL) {
DPRINT_DBG(OUTPUT, "malloc failure\n");
rwl_wifi_free_list(master_list);
return (FAIL);
}
if ((error = remote_CDC_DATA_wifi_rx((void*)wl, rec_frame)) < 0) {
free(rec_frame);
rwl_wifi_free_list(master_list);
return FAIL;
}
if (rec_frame->subtype >= RWL_DEFAULT_WIFI_FRAG_COUNT) {
DPRINT_DBG(OUTPUT, " Read bogus subtype %d\n", rec_frame->subtype);
free(rec_frame);
continue;
}
/* Keep only originals and discard any dup frags */
if (!master_list[rec_frame->subtype]) {
master_list[rec_frame->subtype] = rec_frame;
} else {
num_frags--;
free(rec_frame);
}
/* Look for first frag so we can accurately calculate totalfrag */
if (rec_frame->subtype == RWL_WIFI_DEFAULT_SUBTYPE) {
memcpy((char*)rem_ptr,
(char*)&master_list[rec_frame->subtype]->
data[RWL_WIFI_CDC_HEADER_OFFSET], REMOTE_SIZE);
rwl_swap_header(rem_ptr, NETWORK_TO_HOST);
totalfrag = rem_ptr->msg.len / RWL_WIFI_FRAG_DATA_SIZE;
remainingbytes = rem_ptr->msg.len % RWL_WIFI_FRAG_DATA_SIZE;
}
}
/* All frags are now read and there are no dups. Check for missing frags */
for (seq_num = 0; seq_num < totalfrag; seq_num++) {
if (!master_list[seq_num]) {
DPRINT_DBG(OUTPUT, "Missing frag number %d\n", seq_num);
rwl_wifi_free_list(master_list);
return (FAIL);
}
}
/*
case 1: response in one frame i.e if (totalfrag==0)
case 2: response in multiple frame ( multiple of RWL_WIFI_FRAG_DATA_SIZE)
case 3: response in multiple frame and not in multiple of RWL_WIFI_FRAG_DATA_SIZE
*/
/* case 1: Check for the response in single frame */
if (totalfrag == 0)
memcpy((char*)&input_buf[0],
(char*)&master_list[0]->data[REMOTE_SIZE], rem_ptr->msg.len);
else /* case 2: Copy fragments into contiguous frame */
memcpy((char*)&input_buf[0],
(char*)&master_list[0]->data[REMOTE_SIZE], RWL_WIFI_FRAG_DATA_SIZE);
/*
* If all the frames are recieved , copy them to a contigues buffer
*/
for (seq_num = 1; seq_num < totalfrag; seq_num++) {
memcpy((char*)&input_buf[seq_num*RWL_WIFI_FRAG_DATA_SIZE],
(char*)&master_list[seq_num]->data, RWL_WIFI_FRAG_DATA_SIZE);
}
/* case 3 : if response is in fragments and valid data in the last frame is less
* than RWL_WIFI_FRAG_DATA_SIZE
*/
if (remainingbytes && (totalfrag > 0))
memcpy((char*)&input_buf[seq_num*RWL_WIFI_FRAG_DATA_SIZE],
(char*)&master_list[seq_num]->data, remainingbytes);
if (shell) {
#ifdef LINUX
write(1, (char*)input_buf, strlen((char*)input_buf));
#else
fputs((char*)input_buf, stdout);
#endif /* LINUX */
}
rwl_wifi_free_list(master_list);
return error;
}
/*
* read out all the action frame which are queued in the driver even
* before issuing any wl cmd. This is essential because due to late arrival of frame it can
* get queued after the read expires.
*/
int
rwl_wifi_purge_actionframes(void *wl)
{
dot11_action_wifi_vendor_specific_t *rec_frame;
void *ptr = NULL;
int error = BCME_OK;
if ((rec_frame = (dot11_action_wifi_vendor_specific_t *)
malloc(RWL_WIFI_ACTION_FRAME_SIZE)) == NULL) {
DPRINT_DBG(OUTPUT, "Purge Error in reading the frame \n");
return BCME_NOMEM;
}
for (;;) {
if ((error = rwl_var_getbuf(wl, RWL_WIFI_GET_ACTION_CMD, rec_frame,
RWL_WIFI_ACTION_FRAME_SIZE, &ptr)) < 0) {
DPRINT_DBG(OUTPUT, "rwl_wifi_purge_actionframes:"
"Purge Error in reading the frame \n");
break;
}
memcpy((char*)rec_frame, ptr, RWL_WIFI_ACTION_FRAME_SIZE);
if ((rec_frame->category != RWL_ACTION_WIFI_CATEGORY))
break;
}
free(rec_frame);
return error;
}
/*
* check for the channel of remote and respond if it matches with its current
* channel. Once the server gets the handshake cmd, it will check the channel
* number of the remote with its channel and if it matches , then it send out the
* ack to the remote client. This fucntion is used only by the server.
*/
void
rwl_wifi_find_server_response(void *wl, dot11_action_wifi_vendor_specific_t *rec_frame)
{
int error, send, server_channel;
if (rec_frame->type == RWL_WIFI_FIND_MY_PEER) {
rec_frame->type = RWL_WIFI_FOUND_PEER;
/* read channel on of the SERVER */
rwl_wifi_config_channel(wl, WLC_GET_CHANNEL, &server_channel);
/* overlapping channel not supported,
so server will only respond to client on the channel of the client
*/
if (rec_frame->data[RWL_WIFI_CLIENT_CHANNEL_OFFSET] == server_channel) {
/* send the response by updating server channel in the frame */
rec_frame->data[RWL_WIFI_SERVER_CHANNEL_OFFSET] = server_channel;
/* change the TYPE feild for giving the ACK */
for (send = 0; send < RWL_WIFI_SEND; send++) {
if ((error = rwl_var_send_vs_actionframe(wl,
RWL_WIFI_ACTION_CMD,
rec_frame,
RWL_WIFI_ACTION_FRAME_SIZE)) < 0) {
DPRINT_ERR(ERR, "rwl_wifi_find_server_response: Failed"
"to Send the Frame %d\n", error);
break;
}
rwl_sleep(RWL_WIFI_SEND_DELAY);
}
}
}
return;
}
/*
* This function is used by client only. Sends the finmypeer sync frame to remote
* server on diffrent channels and waits for the response.
*/
int
rwl_find_remote_wifi_server(void *wl, char *id)
{
dot11_action_wifi_vendor_specific_t *rem_wifi_send, *rem_wifi_recv;
rem_ioctl_t *rem_ptr = &rem_cdc;
/* This list is generated considering valid channel and if this
* may requires updation or deletion. This needs to be identified.
* we have assumed that server band is not known and considered all band channels.
*/
int wifichannel[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 36, 40, 44, 48, 149, 153, 157, 161, 165};
int i, error, schannel, channel_count;
struct ether_addr * curr_macaddr;
int ret;
need_speedy_response = TRUE;
if ((rem_wifi_send = rwl_wifi_allocate_actionframe()) == NULL) {
DPRINT_ERR(ERR, " rwl_find_remote_wifi_server : Failed to allocate \n");
return FAIL;
}
if ((rem_wifi_recv = rwl_wifi_allocate_actionframe()) == NULL) {
DPRINT_ERR(ERR, " rwl_find_remote_wifi_server : Failed to allocate\n");
free(rem_wifi_send);
return FAIL;
}
channel_count = sizeof(wifichannel) / sizeof(int);
/* make dummy read to make sure we don't read the already queued
* actionframes against the cmd we issue
*/
if ((error = rwl_wifi_purge_actionframes(wl)) < 0) {
free(rem_wifi_send);
free(rem_wifi_recv);
return error;
}
/* update the client sync specifier */
rem_wifi_send->type = RWL_WIFI_FIND_MY_PEER;
/* update the CDC flag to indicate it is handshake frame */
rem_ptr->msg.cmd = 0;
/* cmd =0 ,this will be ignored when server receive frame
* with REMOTE_FINDSERVER_IOCTL flag
*/
rem_ptr->msg.len = RWL_WIFI_FRAG_DATA_SIZE;
rem_ptr->msg.flags = REMOTE_FINDSERVER_IOCTL;
rem_ptr->data_len = RWL_WIFI_FRAG_DATA_SIZE;
rwl_swap_header(rem_ptr, HOST_TO_NETWORK);
memcpy((char*)&rem_wifi_send->data, (char*)rem_ptr, REMOTE_SIZE);
/* copy server mac to which ref driver needs to send unicast action frame */
memcpy((char*)&rem_wifi_send->data[RWL_REF_MAC_ADDRESS_OFFSET], &id[0], ETHER_ADDR_LEN);
if ((ret = rwl_var_getbuf(wl, "cur_etheraddr", NULL, 0, (void**) &curr_macaddr)) < 0) {
DPRINT_ERR(ERR, "Error getting current Mac addr \n");
return FAIL;
}
memcpy((char*)&rem_wifi_send->data[RWL_DUT_MAC_ADDRESS_OFFSET], (char*)curr_macaddr->octet,
ETHER_ADDR_LEN);
/* Start with the channel in the list and keep changing till the server
* responds or channels list ends
*/
for (i = 0; i < channel_count; i++) {
DPRINT_INFO(OUTPUT, "Scanning Channel: %d ...\n", wifichannel[i]);
if ((error = rwl_wifi_config_channel(wl, WLC_SET_CHANNEL,
&wifichannel[i])) < 0) {
DPRINT_ERR(ERR, " Failed to set the specified channel %d\n",
wifichannel[i]);
break;
}
/* send channel detail of client to server */
rem_wifi_send->data[RWL_WIFI_CLIENT_CHANNEL_OFFSET] = wifichannel[i];
if ((error = rwl_var_send_vs_actionframe(wl, RWL_WIFI_ACTION_CMD, rem_wifi_send,
RWL_WIFI_ACTION_FRAME_SIZE)) < 0) {
DPRINT_DBG(OUTPUT, "Failed to Send the Frame %d\n", error);
break;
}
/* read the server response on the same channel */
if ((error = remote_CDC_DATA_wifi_rx(wl, rem_wifi_recv)) < 0) {
rwl_sleep(RWL_CHANNEL_SCAN_WAIT);
continue;
}
/* Verify for the Type RWL_WIFI_FOUND_PEER */
if (rem_wifi_recv->type == RWL_WIFI_FOUND_PEER) {
if (rem_wifi_recv->data[RWL_WIFI_SERVER_CHANNEL_OFFSET] ==
rem_wifi_recv->data[RWL_WIFI_CLIENT_CHANNEL_OFFSET]) {
DPRINT_INFO(OUTPUT, "Server is on channel # %d\n",
rem_wifi_recv->data[RWL_WIFI_SERVER_CHANNEL_OFFSET]);
schannel = rem_wifi_recv->data[RWL_WIFI_SERVER_CHANNEL_OFFSET];
/* Set the back to the channel on which REF was originally */
if ((error = rwl_wifi_config_channel(wl,
WLC_SET_CHANNEL, &schannel) < 0)) {
DPRINT_ERR(ERR, "Failed to set the specified"
"channel %d\n", schannel);
} else {
DPRINT_ERR(ERR, "REF now moved to the"
"channel of server # %d\n", schannel);
}
need_speedy_response = FALSE;
/* we are done here, end the loop */
break;
} else {
DPRINT_INFO(OUTPUT, "Server is operating on diffrent channel."
"continue scanning\n");
}
}
/* before chaning the channel of client and sending sync frame
* wait for while and send
*/
rwl_sleep(RWL_CHANNEL_SCAN_WAIT);
}
need_speedy_response = FALSE;
free(rem_wifi_send);
free(rem_wifi_recv);
return error;
}
#endif /* RWL_WIFI */
#ifdef RWL_DONGLE
static int
remote_CDC_tx_dongle(void *wl, rem_ioctl_t *rem_ptr, uchar *buf)
{
unsigned long numwritten;
char end_of_packet[END_OF_PACK_SEP_LEN] = "\n\n";
uchar loc_buf[UART_FIFO_LEN];
uint len = END_OF_PACK_SEP_LEN;
uint noframes, frame_count, rem_bytes;
uint n_bytes;
uint data_len;
/* Converting the CDC header with keyword 'rwl ' in ascii format
* as dongle UART understands only ascii format.
* In dongle UART driver CDC structure is made from the ascii data
* it received.
*/
sprintf((char*)loc_buf, "rwl %d %d %d %d ", rem_ptr->msg.cmd, rem_ptr->msg.len,
rem_ptr->msg.flags, rem_ptr->data_len);
n_bytes = (uint)strlen((char*)loc_buf);
data_len = ltoh32(rem_ptr->data_len);
DPRINT_DBG(OUTPUT, "rwl %x %d %d %d ", ltoh32(rem_ptr->msg.cmd), ltoh32(rem_ptr->msg.len),
ltoh32(rem_ptr->msg.flags), data_len);
DPRINT_DBG(OUTPUT, "CDC Header:No of bytes to be sent=%d\n", n_bytes);
DPRINT_DBG(OUTPUT, "Data:No of bytes to be sent=%d\n", data_len);
/* Send the CDC Header */
if (rwl_write_serial_port(wl, (char*)loc_buf, n_bytes, &numwritten) < 0) {
DPRINT_ERR(ERR, "CDC_Tx: Header: Write failed\n");
DPRINT_ERR(ERR, "CDC_Tx: Header: numwritten %ld != n_bytes %d\n",
numwritten, n_bytes);
return (FAIL);
}
/* Dongle UART FIFO len is 64 bytes and flow control is absent.
* While transmitting large chunk of data the data was getting lost
* at UART driver so for large chunk of data 64 bytes are sent at a time
* folowed by delay and then next set of 64 bytes and so on.
* For data which is less than 64 bytes it is sent in one shot
*/
noframes = rem_ptr->data_len/UART_FIFO_LEN;
if (noframes == 0) {
/* Send the data now */
if (rwl_write_serial_port(wl, (char*)buf, rem_ptr->data_len, &numwritten) < 0) {
DPRINT_ERR(ERR, "Data_Tx: Header: Write failed\n");
DPRINT_ERR(ERR, "Data_Tx: Header: numwritten %ld != len %d\n",
numwritten, rem_ptr->data_len);
return (FAIL);
}
} else {
if (rem_ptr->data_len % UART_FIFO_LEN == 0) {
rem_bytes = UART_FIFO_LEN;
} else {
rem_bytes = rem_ptr->data_len % UART_FIFO_LEN;
noframes += 1;
}
for (frame_count = 0; frame_count < noframes; frame_count++) {
if (frame_count != noframes-1) {
memcpy(loc_buf, (char*)(&buf[frame_count*UART_FIFO_LEN]),
UART_FIFO_LEN);
/* Send the data now */
if (rwl_write_serial_port(wl, (char*)loc_buf, UART_FIFO_LEN,
&numwritten) == -1) {
DPRINT_ERR(ERR, "Data_Tx: Header: Write failed\n");
return (-1);
}
} else {
memcpy(loc_buf, (char*)(&buf[frame_count*UART_FIFO_LEN]),
rem_bytes);
if (rwl_write_serial_port(wl, (char*)loc_buf, rem_bytes,
&numwritten) == -1) {
DPRINT_ERR(ERR, "Data_Tx: Header: Write failed\n");
return (-1);
}
}
rwl_sleep(SYNC_TIME);
}
}
/* Send end of packet now */
if (rwl_write_serial_port(wl, end_of_packet, len, &numwritten) == -1) {
DPRINT_ERR(ERR, "CDC_Tx: Header: Write failed\n");
DPRINT_ERR(ERR, "CDC_Tx: Header: numwritten %ld != len %d\n",
numwritten, len);
return (FAIL);
}
DPRINT_DBG(OUTPUT, "Packet sent!\n");
/* Return size of actual buffer to satisfy accounting going on above this level */
return (ltoh32(rem_ptr->msg.len));
}
#endif /* RWL_DONGLE */
#if defined(RWL_SERIAL) || defined(RWL_DONGLE)|| defined(RWL_SOCKET)
void *
rwl_open_pipe(int remote_type, char *port, int ReadTotalTimeout, int debug)
{
return rwl_open_transport(remote_type, port, ReadTotalTimeout, debug);
}
int
rwl_close_pipe(int remote_type, void* handle)
{
return rwl_close_transport(remote_type, handle);
}
#endif
int
remote_CDC_tx(void *wl, uint cmd, uchar *buf, uint buf_len, uint data_len, uint flags, int debug)
{
#ifdef RWL_SERIAL
unsigned long numwritten = 0;
#endif
rem_ioctl_t *rem_ptr = &rem_cdc;
#ifdef RWL_WIFI
int error;
uint totalframes, tx_count;
dot11_action_wifi_vendor_specific_t *rem_wifi_send;
#endif
UNUSED_PARAMETER(debug);
UNUSED_PARAMETER(buf);
UNUSED_PARAMETER(wl);
memset(rem_ptr, 0, sizeof(rem_ioctl_t));
rem_ptr->msg.cmd = cmd;
rem_ptr->msg.len = buf_len;
rem_ptr->msg.flags = flags;
rem_ptr->data_len = data_len;
if (strlen(g_rem_ifname) != 0) {
strncpy(rem_ptr->intf_name, g_rem_ifname, (int)IFNAMSIZ - 1);
rem_ptr->intf_name[IFNAMSIZ - 1] = '\0';
}
rwl_swap_header(rem_ptr, HOST_TO_NETWORK);
if (data_len > buf_len) {
DPRINT_ERR(ERR, "remote_CDC_tx: data_len (%d) > buf_len (%d)\n", data_len, buf_len);
return (FAIL);
}
#ifdef RWL_SERIAL
if (remote_type == REMOTE_SERIAL) {
int ret;
/* Send CDC header first */
if ((ret = rwl_write_serial_port(wl, (char *)rem_ptr,
REMOTE_SIZE, &numwritten)) == -1) {
DPRINT_ERR(ERR, "CDC_Tx: Data: Write failed \n");
return (FAIL);
}
numwritten = ret;
/* Send data second */
if ((ret = rwl_write_serial_port(wl, (char*)buf,
data_len, &numwritten)) == -1) {
DPRINT_ERR(ERR, "CDC_Tx: Data: Write failed \n");
return (FAIL);
}
numwritten = ret;
return (buf_len);
}
#endif /* RWL_SERIAL */
#ifdef RWL_DONGLE
if (remote_type == REMOTE_DONGLE) {
return (remote_CDC_tx_dongle(wl, rem_ptr, buf));
}
#endif /* RWL_DONGLE */
#ifdef RWL_SOCKET
if (remote_type == REMOTE_SOCKET) {
int ret;
/* Send CDC header first */
if ((ret = rwl_send_to_streamsocket(*(int*)wl, (char *)rem_ptr,
REMOTE_SIZE, 0)) == -1) {
DPRINT_ERR(ERR, "CDC_Tx: Data: Write failed \n");
return (FAIL);
}
/* Send data second */
if ((ret = rwl_send_to_streamsocket(*(int*)wl, (const char*)buf,
data_len, 0)) == -1) {
DPRINT_ERR(ERR, "CDC_Tx: Data: Write failed \n");
return (FAIL);
}
return (buf_len);
}
#endif /* RWL_SOCKET */
#ifdef RWL_WIFI
/*
* wifi action frame is formed based on the CDC header and data.
* If the data is bigger than RWL_WIFI_FRAG_DATA_SIZE size, number of fragments are
* calculated and sent
* similar number of action frames with subtype incremented with sequence.
* Frames are sent with delay to avoid the outof order at receving end
*/
if (remote_type == REMOTE_WIFI) {
if ((rem_wifi_send = rwl_wifi_allocate_actionframe()) == NULL) {
DPRINT_ERR(ERR, "remote_CDC_tx: Failed to get allocated buffer\n");
return (FAIL);
}
if (buf_len > RWL_WIFI_FRAG_DATA_SIZE) {
/* response needs to be sent in fragments */
totalframes = buf_len / RWL_WIFI_FRAG_DATA_SIZE;
memcpy((char*)&rem_wifi_send->data[RWL_WIFI_CDC_HEADER_OFFSET],
(char*)rem_ptr, REMOTE_SIZE);
memcpy((char*)&rem_wifi_send->data[REMOTE_SIZE], &buf[0],
RWL_WIFI_FRAG_DATA_SIZE);
/* update type feild to inform receiver it's frammeted response frame
*/
rem_wifi_send->type = RWL_ACTION_WIFI_FRAG_TYPE;
rem_wifi_send->subtype = RWL_WIFI_DEFAULT_SUBTYPE;
if ((error = rwl_var_send_vs_actionframe(wl, RWL_WIFI_ACTION_CMD,
rem_wifi_send, RWL_WIFI_ACTION_FRAME_SIZE)) < 0) {
DPRINT_DBG(OUTPUT, "Failed to Send the Frame %d\n", error);
free(rem_wifi_send);
return error;
}
/* Send remaining bytes in fragments */
for (tx_count = 1; tx_count < totalframes; tx_count++) {
rem_wifi_send->type = RWL_ACTION_WIFI_FRAG_TYPE;
rem_wifi_send->subtype = tx_count;
/* First frame onwards , buf contains only data */
memcpy((char*)&rem_wifi_send->data,
&buf[tx_count*RWL_WIFI_FRAG_DATA_SIZE], RWL_WIFI_FRAG_DATA_SIZE);
if ((error = rwl_var_send_vs_actionframe(wl, RWL_WIFI_ACTION_CMD,
rem_wifi_send, RWL_WIFI_ACTION_FRAME_SIZE)) < 0) {
free(rem_wifi_send);
return error;
}
rwl_sleep(RWL_WIFI_SEND_DELAY);
}
/* Check for remaing bytes to send */
if ((totalframes*RWL_WIFI_FRAG_DATA_SIZE) != buf_len) {
rem_wifi_send->type = RWL_ACTION_WIFI_FRAG_TYPE;
rem_wifi_send->subtype = tx_count;
memcpy((char*)&rem_wifi_send->data,
&buf[tx_count*RWL_WIFI_FRAG_DATA_SIZE],
(buf_len - (tx_count*RWL_WIFI_FRAG_DATA_SIZE)));
if ((error = rwl_var_send_vs_actionframe(wl, RWL_WIFI_ACTION_CMD,
rem_wifi_send, RWL_WIFI_ACTION_FRAME_SIZE)) < 0) {
free(rem_wifi_send);
return error;
}
}
} else {
/* response fits to single frame */
memcpy((char*)&rem_wifi_send->data[RWL_WIFI_CDC_HEADER_OFFSET],
(char*)rem_ptr, REMOTE_SIZE);
/* when data_len is 0 , buf will be NULL */
if (buf != NULL) {
memcpy((char*)&rem_wifi_send->data[REMOTE_SIZE],
&buf[0], data_len);
}
error = rwl_var_send_vs_actionframe(wl, RWL_WIFI_ACTION_CMD, rem_wifi_send,
RWL_WIFI_ACTION_FRAME_SIZE);
free(rem_wifi_send);
return error;
}
}
#endif /* RWL_WIFI */
return (0);
}
rem_ioctl_t *
remote_CDC_rx_hdr(void *remote, int debug)
{
#ifdef RWL_SOCKET
int ret;
#endif /* RWL_SOCKET */
#if defined(RWL_SERIAL) || defined(RWL_DONGLE) || defined(RWL_SOCKET)
uint numread = 0;
#endif
rem_ioctl_t *rem_ptr = &rem_cdc;
memset(rem_ptr, 0, sizeof(rem_ioctl_t));
UNUSED_PARAMETER(remote);
UNUSED_PARAMETER(debug);
switch (remote_type) {
#if defined(RWL_SERIAL) || defined(RWL_DONGLE)
case REMOTE_SERIAL:
case REMOTE_DONGLE:
if (rwl_read_serial_port(remote, (char *)rem_ptr, sizeof(rem_ioctl_t),
&numread) < 0) {
DPRINT_ERR(ERR, "remote_CDC_rx_hdr: Header Read failed \n");
return (NULL);
}
break;
#endif /* RWL_SERIAL | RWL_DONGLE */
#ifdef RWL_SOCKET
case REMOTE_SOCKET:
ret = rwl_receive_from_streamsocket(*(int*)remote, (char *)rem_ptr,
sizeof(rem_ioctl_t), 0);
numread = ret;
if (ret == -1) {
DPRINT_ERR(ERR, "remote_CDC_rx_hdr: numread:%d\n", numread);
return (NULL);
}
if (numread == 0) {
DPRINT_DBG(OUTPUT, "\n remote_CDC_rx_hdr:No data to receive\n");
return NULL;
}
break;
#endif
default:
DPRINT_ERR(ERR, "\n Unknown Transport Type\n");
break;
}
return (rem_ptr);
}
/* Return a CDC type buffer */
int
remote_CDC_rx(void *wl, rem_ioctl_t *rem_ptr, uchar *readbuf, uint buflen, int debug)
{
uint numread = 0;
#ifdef RWL_SOCKET
int ret;
#endif
#ifdef RWL_WIFI
UNUSED_PARAMETER(numread);
#endif /* RWL_WIFI */
UNUSED_PARAMETER(wl);
UNUSED_PARAMETER(readbuf);
UNUSED_PARAMETER(buflen);
UNUSED_PARAMETER(debug);
UNUSED_PARAMETER(numread);
if (rem_ptr->data_len > rem_ptr->msg.len) {
DPRINT_ERR(ERR, "remote_CDC_rx: remote data len (%d) > msg len (%d)\n",
rem_ptr->data_len, rem_ptr->msg.len);
return (FAIL);
}
#if defined(RWL_DONGLE) || defined(RWL_SERIAL)
if ((remote_type == REMOTE_DONGLE) || (remote_type == REMOTE_SERIAL)) {
if (rwl_read_serial_port(wl, (char*)readbuf, rem_ptr->data_len,
&numread) < 0) {
DPRINT_ERR(ERR, "remote_CDC_rx_hdr: Data Receivefailed \n");
return (FAIL);
}
}
#endif /* RWL_DONGLE || RWL_SERIAL */
#ifdef RWL_SOCKET
if (remote_type == REMOTE_SOCKET) {
if (((ret = rwl_receive_from_streamsocket(*(int*)wl, (char*)readbuf,
rem_ptr->data_len, 0)) == -1)) {
DPRINT_ERR(ERR, "remote_CDC_rx:Data Receive failed\n");
return (FAIL);
}
}
#endif /* RWL_SOCKET */
return (SUCCESS);
}
#ifdef RWL_SOCKET
int
rwl_sockconnect(int SockDes, struct sockaddr *servAddr, int size)
{
DPRINT_DBG(OUTPUT, "sockconnet SockDes=%d\n", SockDes);
if (rwl_connectsocket(SockDes, servAddr, size) < 0) {
DPRINT_ERR(ERR, "\n Server is not running\n");
return FAIL;
}
return SUCCESS;
}
#endif /* RWL_SOCKET */
void
rwl_swap_header(rem_ioctl_t *rem_ptr, bool host_to_network)
{
rem_ptr->msg.cmd = host_to_network?(htol32(rem_ptr->msg.cmd)):(ltoh32(rem_ptr->msg.cmd));
rem_ptr->msg.len = host_to_network?(htol32(rem_ptr->msg.len)):(ltoh32(rem_ptr->msg.len));
rem_ptr->msg.flags = host_to_network?(htol32(rem_ptr->msg.flags)):
(ltoh32(rem_ptr->msg.flags));
rem_ptr->msg.status = host_to_network?(htol32(rem_ptr->msg.status)):
(ltoh32(rem_ptr->msg.status));
rem_ptr->data_len = host_to_network?(htol32(rem_ptr->data_len)):(ltoh32(rem_ptr->data_len));
}