/* This routine is used for both Get and Set Ioctls for the socket */
static int
rwl_information_socket(void *wl, int cmd, void* input_buf, unsigned long *input_len,
	unsigned long *tx_len, uint flags)
{
	int error, Sockfd;
	rem_ioctl_t *rem_ptr = NULL;

	if ((Sockfd = rwl_connect_socket_server()) < 0) {
		DPRINT_ERR(ERR, "Error in getting the Socket Descriptor\n");
		return FAIL;
	}
	wl = (void *)(&Sockfd);

	if (remote_CDC_tx(wl, cmd, input_buf, *input_len,
		*tx_len, flags, 0) < 0) {
		DPRINT_ERR(ERR, "query_info_fe: Send command failed\n");
		rwl_close_pipe(remote_type, wl);
		return FAIL;
	}

	if ((rem_ptr = remote_CDC_rx_hdr(wl, 0)) == NULL) {
		DPRINT_ERR(ERR, "query_info_fe: Reading CDC header 	failed\n");
		rwl_close_pipe(remote_type, wl);
		return FAIL;
	}
	rwl_swap_header(rem_ptr, NETWORK_TO_HOST);

	if (rem_ptr->msg.len > *input_len) {
		DPRINT_ERR(ERR, "query_info_fe: needed size(%d) > "
		           "actual size(%ld)\n", rem_ptr->msg.len, *input_len);
		rwl_close_pipe(remote_type, wl);
		return FAIL;
	}

	if (remote_CDC_rx(wl, rem_ptr, input_buf, *input_len, 0) == FAIL) {
		DPRINT_ERR(ERR, "query_info_fe: No results!\n");
		rwl_close_pipe(remote_type, wl);
		return FAIL;
	}

	if (rem_ptr->msg.flags & REMOTE_REPLY)
		error = rem_ptr->msg.cmd;
	else
		error = 0;

	rwl_close_pipe(remote_type, wl);

	return error;
}
int
remote_CDC_tx(void *wl, uint cmd, uchar *buf, uint buf_len, uint data_len, uint flags, int debug)
{
#if defined(RWL_SOCKET) || defined(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);

	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);
	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);
		}
		numwritten = ret;

		/* 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);
		}
		numwritten = ret;

		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);
}
/*
 * 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
	 */
	rwl_wifi_purge_actionframes(wl);

	/* 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;
}
/*
 * 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) {
		write(1, (char*)input_buf, strlen((char*)input_buf));
	}

	rwl_wifi_free_list(master_list);
	return error;
}
/*
 * 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;
}
/*
* This is the front end query function for Set Ioctls. This is used by clients
for executing Set Ioctls.
*/
int
rwl_setinformation_fe(void *wl, int cmd, void* buf,
	unsigned long *len, int debug, int rem_ioctl_select) {
	int error = 0;
	uint tx_len;
#if defined  (RWL_SERIAL) || (RWL_WIFI)
	rem_ioctl_t *rem_ptr = NULL;
#endif

#ifdef RWL_WIFI
	dot11_action_wifi_vendor_specific_t *list = NULL;
	char *cbuf, retry;
#endif

	UNUSED_PARAMETER(debug);

	switch (remote_type) {
		case REMOTE_SOCKET:
#ifdef RWL_SOCKET
			error = rwl_information_socket(wl, cmd, buf, len, len, rem_ioctl_select);
#endif
			break;
#ifdef RWL_SERIAL
		case REMOTE_SERIAL:
			if (remote_CDC_tx(wl, cmd, buf, *len, *len, rem_ioctl_select, debug) < 0) {
				DPRINT_ERR(ERR, "set_info_fe: Send command failed\n");
				return FAIL;
			}

			if ((rem_ptr = remote_CDC_rx_hdr(wl, debug)) == NULL) {
				DPRINT_ERR(ERR, "set_info_fe: Reading CDC header failed\n");
				return FAIL;
			}

			if (rem_ptr->msg.flags != REMOTE_REPLY)	{
				DPRINT_ERR(ERR, "set_info_fe: response format error.\n");
				return FAIL;
			}

			if (rem_ptr->msg.len > *len) {
				DPRINT_ERR(ERR, "set_info_fe: needed size (%d) greater than "
					   "actual size (%lu)\n", rem_ptr->msg.len, *len);
				return FAIL;
			}

			error = rem_ptr->msg.cmd;
			if (error != 0) {
				DPRINT_ERR(ERR, "set_info_fe: remote cdc header return "
					   "error code (%d)\n", error);
			}

			if (remote_CDC_rx(wl, rem_ptr, buf, rem_ptr->msg.len, debug) == -1) {
				DPRINT_ERR(ERR, "set_info_fe: fetching results failed\n");
				return FAIL;
			}

			if (rem_ptr->msg.flags & REMOTE_REPLY)
				error = rem_ptr->msg.cmd;
			break;
#endif /* RWL_SERIAL */
#ifdef RWL_DONGLE
		case REMOTE_DONGLE:
			if ((int)(*len) > SERVER_RESPONSE_MAX_BUF_LEN)
				*len = SERVER_RESPONSE_MAX_BUF_LEN;

			/* Actual buffer to be sent should be max 256 bytes as
			 *UART input buffer
			 * is 512 bytes
			 */
			tx_len = MIN(*len, 512);
			error = rwl_information_dongle(wl, cmd, buf, len, tx_len, rem_ioctl_select);
			break;
#endif //ifdef RWL_DONGLE
		case REMOTE_WIFI:
#ifdef RWL_WIFI
			if ((int)(*len) > SERVER_RESPONSE_MAX_BUF_LEN)
				*len = SERVER_RESPONSE_MAX_BUF_LEN;

			/* Actual buffer to be sent should be max 960 bytes
			 * as wifi max frame size if 960
			 * and actual data for any command will not exceed 960 bytes
			*/
			tx_len = MIN(*len, RWL_WIFI_FRAG_DATA_SIZE);

			if ((cbuf = (char*) malloc(tx_len)) == NULL) {
				DPRINT_ERR(ERR, "Malloc failed for set_info_fe character buf\n");
				return FAIL;
			}
			if ((list = (dot11_action_wifi_vendor_specific_t *)
					malloc(RWL_WIFI_ACTION_FRAME_SIZE)) == NULL) {
				free(cbuf);
				return FAIL;
			}

			if ((rem_ptr = (rem_ioctl_t *)malloc(sizeof(rem_ioctl_t))) == NULL) {
				free(list);
				free(cbuf);
				return FAIL;
			}

			memcpy(cbuf, (char*)buf, tx_len);

			for (retry = 0; retry < RWL_WIFI_RETRY; retry++) {

				rwl_wifi_purge_actionframes(wl);
				/* copy back the buffer to input buffer */
				memcpy((char*)buf, (char*)cbuf, tx_len);

				if (retry > 3)
					DPRINT_INFO(OUTPUT, "retry %d cmd %d\n", retry, cmd);

				if ((error = remote_CDC_wifi_tx(wl, cmd, buf, *len,
				                                tx_len, rem_ioctl_select) < 0)) {
					DPRINT_ERR(ERR, "ir_setinformation_fe: Send"
					"command failed\n");
					rwl_sleep(RWL_WIFI_RETRY_DELAY);
					continue;
				}

				if ((char*)buf != NULL) {
					/* In case cmd is findserver, response is not
					 * required from the server
					 */
					if (!strcmp((char*)buf, RWL_WIFI_FIND_SER_CMD)) {
						break;
					}
				}

				/* Read the CDC header and data of for the sent cmd
				 * resposne
				 */
				if ((error = remote_CDC_DATA_wifi_rx((void*)wl, list) < 0)) {
					DPRINT_ERR(ERR, "ir_setinformation_fe: failed to read"
						"the response\n");
					rwl_sleep(RWL_WIFI_RETRY_DELAY);
					continue;
				}

				memcpy((char*)rem_ptr,
				(char*)&list->data[RWL_WIFI_CDC_HEADER_OFFSET],
				REMOTE_SIZE);
				rwl_swap_header(rem_ptr, NETWORK_TO_HOST);

				memcpy((char*)buf, (char*)&list->data[REMOTE_SIZE],
				rem_ptr->msg.len);

				if (rem_ptr->msg.flags & REMOTE_REPLY) {
					error = rem_ptr->msg.cmd;
					break;
				} else {
					rwl_sleep(RWL_WIFI_RETRY_DELAY);
				}
			}
				free(rem_ptr);
				free(list);
			if (cbuf != NULL)
				free(cbuf);
			break;
#endif /* RWL_WIFI */
		default:
			DPRINT_ERR(ERR, "rwl_setinformation_fe: Unknown remote_type:%d\n",
			remote_type);
		break;
	}

	return error;
}
/* Issue shell commands independent of transport type and return result */
static int
rwl_shell_information_fe(void *wl, int cmd, uchar* input_buf, unsigned long *input_len)
{
	int error = 0, remote_cmd;
	uchar* resp_buf = NULL;
	rem_ioctl_t *rem_ptr = NULL;

#ifdef RWL_WIFI
	char *cbuf, retry;
	dot11_action_wifi_vendor_specific_t *list;
#endif

#ifdef RWL_SOCKET
	int Sockfd;
#endif

	remote_cmd = REMOTE_SHELL_CMD;

#ifdef RWLASD
	if (cmd == ASD_CMD)
		remote_cmd = REMOTE_ASD_CMD;
#endif
	if (cmd == VISTA_CMD)
		remote_cmd = REMOTE_VISTA_CMD;

	switch (remote_type) {
		case REMOTE_SOCKET:
#ifdef RWL_SOCKET
			if ((Sockfd = rwl_connect_socket_server()) < 0) {
				DPRINT_ERR(ERR, " Error in getting the SocDes\n");
				return BCME_ERROR;
			}

			wl = (void *)(&Sockfd);
			if (remote_CDC_tx(wl, cmd, input_buf, *input_len, *input_len,
				remote_cmd, 0) < 0) {
				DPRINT_ERR(ERR, "shell_info_fe: Send command failed\n");
				rwl_close_pipe(remote_type, wl);
				return BCME_ERROR;
			}
			/* For backward compatibility for ASD, async and kill commands do the
			 * old way
			 */
			if (remote_cmd == REMOTE_SHELL_CMD && !strstr((char*)input_buf, "%") &&
				!strstr((char*)input_buf, "kill"))
				error = rwl_socket_shellresp(wl, rem_ptr, input_buf);
			else {
				if ((rem_ptr = remote_CDC_rx_hdr(wl, 0)) == NULL) {
					DPRINT_ERR(ERR, "shell_info_fe: Receiving CDC"
						"header failed\n");
					rwl_close_pipe(remote_type, wl);
					return FAIL;
				}

				if ((resp_buf = malloc(rem_ptr->msg.len + 1)) == NULL) {
					DPRINT_ERR(ERR, "Mem alloc fails\n");
					rwl_close_pipe(remote_type, wl);
					return FAIL;
				}

				if (remote_CDC_rx(wl, rem_ptr, resp_buf,
					rem_ptr->msg.len, 0) == FAIL) {
					DPRINT_ERR(ERR, "shell_info_fe: No results!\n");
					rwl_close_pipe(remote_type, wl);
					free(resp_buf);
					return FAIL;
				}

				/* print the shell result */
				resp_buf[rem_ptr->msg.len] = '\0';
				/* The return value of the shell command
				 * will be stored in rem_ptr->msg.cmd
				 * Return that value to the client process
				 */
				if (rem_ptr->msg.flags & REMOTE_REPLY)
					error = rem_ptr->msg.cmd;
				fputs((char*)resp_buf, stdout);
			}
			rwl_close_pipe(remote_type, wl);
#endif /* RWL_SOCKET */
			break;
#if defined( RWL_DONGLE ) || defined( RWL_SERIAL )
		case REMOTE_DONGLE:
		case REMOTE_SERIAL:
			if (remote_CDC_tx(wl, cmd, input_buf, *input_len, *input_len,
			                  remote_cmd, 0) < 0) {
				DPRINT_ERR(ERR, "shell_info_fe: Send command failed\n");
				return FAIL;
			}

			/* For backward compatibility for ASD, async and kill commands do the
			 * old way
			 */
//			if (remote_cmd != REMOTE_ASD_CMD && !strstr((char*)input_buf, "%") &&
//				!strstr((char*)input_buf, "kill"))
//				error = rwl_dongle_shellresp(wl, rem_ptr, input_buf, cmd);
//			else 
			{
				if ((rem_ptr = remote_CDC_rx_hdr(wl, 0)) == NULL) {
					DPRINT_ERR(ERR, "shell_info_fe:"
					"Receiving CDC header failed\n");
					return BCME_SERIAL_PORT_ERR;
				}
			rwl_swap_header(rem_ptr, NETWORK_TO_HOST);
			/* In case of shell or ASD commands the response
			 * size is not known in advance
			 * Hence based on response from the server memory is allocated
			 */
			if ((resp_buf = malloc(rem_ptr->msg.len + 1)) == NULL) {
				DPRINT_ERR(ERR, "Mem alloc fails for shell response buffer\n");
				return FAIL;
			}

			if (rem_ptr->data_len < DATA_FRAME_LEN) {
				/* Response comes in one shot not in fragments */
				if (remote_CDC_rx(wl, rem_ptr, resp_buf,
					rem_ptr->msg.len, 0) == FAIL) {
					DPRINT_ERR(ERR, "shell_info_fe: No results!\n");
					free(resp_buf);
					return FAIL;
				}
			} else {
				error = rwl_serial_fragmented_response_fe(wl, rem_ptr,
					resp_buf, (unsigned long *)&(rem_ptr->msg.len));
			}
			/* print the shell result */
			resp_buf[rem_ptr->msg.len] = '\0';
			/* The return value of the shell command will be stored in rem_ptr->msg.cmd
			 * Return that value to the client process
			 */
				if (rem_ptr->msg.flags & REMOTE_REPLY)
					error = rem_ptr->msg.cmd;
			fputs((char*)resp_buf, stdout);
			}
			break;
#endif //if defined( RWL_DONGLE ) || defined( RWL_SERIAL )

		case REMOTE_WIFI:
#ifdef RWL_WIFI
			/* Unlike dongle or UART case the response for wi-fi comes in single frame.
			 * (CDC header + data). Hence the single read is called for header and data.
			 * If any error in reading then we sleep for some time before retrying.
			 */
			if ((list = (dot11_action_wifi_vendor_specific_t *)
				malloc(RWL_WIFI_ACTION_FRAME_SIZE)) == NULL) {
				return FAIL;
			}
			if ((rem_ptr = (rem_ioctl_t *)malloc(REMOTE_SIZE)) == NULL) {
				free(list);
				return FAIL;
			}

			if ((cbuf = (char*) malloc(*input_len)) == NULL) {
				DPRINT_ERR(ERR, "Malloc failed for shell response\n");
				free(rem_ptr);
				free(list);
				return FAIL;
			}

			/* copy of the original buf is required for retry */
			memcpy(cbuf, (char*)input_buf, *input_len);
			for (retry = 0; retry < RWL_WIFI_RETRY; retry++) {

				rwl_wifi_purge_actionframes(wl);
				if (remote_CDC_tx(wl, cmd, input_buf, *input_len, *input_len,
				remote_cmd, 0) < 0) {
						DPRINT_DBG(OUTPUT, "rwl_shell_information_fe(wifi):"
							"Send command failed\n");
						rwl_sleep(RWL_WIFI_RETRY_DELAY);
						free(rem_ptr);
						free(list);
						return FAIL;
				}
				/* For backward compatibility for ASD,
				 * async and kill commands do the
				 * old way
				 */
				if (remote_cmd == REMOTE_SHELL_CMD &&
					!strstr((char*)input_buf, "%") &&
					!strstr((char*)input_buf, "kill")) {
					error = rwl_wifi_shellresp(wl, rem_ptr, input_buf);
						if (rem_ptr->msg.len == 0)
						break;
					}
				else if (remote_cmd == REMOTE_VISTA_CMD) {
					if ((error = remote_CDC_DATA_wifi_rx_frag(wl, rem_ptr, 0,
					NULL, RWL_WIFI_SHELL_CMD)) < 0) {
						DPRINT_DBG(OUTPUT, "rwl_shell_information_fe(wifi):"
						"error in reading shell response\n");
						continue;
					}
					if (rem_ptr->msg.flags & REMOTE_REPLY) {
						 error = rem_ptr->msg.cmd;
						 break;
					} else {
						rwl_sleep(RWL_WIFI_RETRY_DELAY);
						continue;
					}
				}
				else {
					/* ASD commands may take long time to give back
					* the response (eg: file transfer)
					*/
					if (remote_cmd == REMOTE_ASD_CMD) {
						for (;;) {
						/* copy back the buffer to input buffer */
						memcpy((char*)input_buf, cbuf, *input_len);

							if ((error = remote_CDC_DATA_wifi_rx_frag(
								wl, rem_ptr, 0, NULL,
								RWL_WIFI_SHELL_CMD)) < 0) {
								DPRINT_DBG(OUTPUT,
								"rwl_shell_information_fe(wifi):"
								"err in reading shell response\n");
								continue;
							}
							if (rem_ptr->msg.flags & REMOTE_REPLY) {
								error = rem_ptr->msg.cmd;
								retry = RWL_WIFI_RETRY;
								break;
							} else {
								rwl_sleep(RWL_WIFI_RETRY_DELAY);
								continue;
							}
						}
					}
				}

			}
			free(rem_ptr);
			free(list);
			if (cbuf != NULL)
				free(cbuf);
#endif /* RWL_WIFI */
			break;

		default:
			break;
	} /* End of switch (remote_type) */

	if (resp_buf)
		free(resp_buf);

	return error;
}
示例#8
0
/* Function: remote_rx_header
 * This function will receive the CDC header from client
 * for socket transport
 * It will receive the command or ioctl from dongle driver for
 * dongle UART serial transport and wifi transport.
 * Arguments: wl - handle to driver
 *          : Des - Socket Descriptor to pass in AcceptConnection
 *          : g_rwl_hndle - Return socket handle that is used for transmission
 *          :           and reception of data in case of socket
 *                        In case of serial, it is just a return value
 */
static int
remote_rx_header(void *wl, int trans_Des)
{
	UNUSED_PARAMETER(wl);
	UNUSED_PARAMETER(trans_Des);

#ifdef RWL_SOCKET
	{
		struct sockaddr_in ClientAddress;
		int SizeOfCliAdd = sizeof(ClientAddress);

		/* Get the socket handle g_rwl_hndle for transmission & reception */
		if ((g_rwl_hndle = rwl_acceptconnection(trans_Des,
		                                        (struct sockaddr *)&ClientAddress,
		                                        &SizeOfCliAdd)) == BCME_ERROR) {
			return BCME_ERROR;
		}

		/* Get CDC header in order to determine buffer requirements */
		if ((g_rem_ptr = remote_CDC_rx_hdr((void *)&g_rwl_hndle, 0)) == NULL) {
			DPRINT_DBG(OUTPUT, "\n Waiting for client to transmit command\n");
			return BCME_ERROR;
		}
	}
#endif /* RWL_SOCKET */

#ifdef RWL_DONGLE
	{
		void *pkt_ptr = NULL;
		int error;

		/* wl driver is polled after every 200 ms (POLLING_TIME) */
		rwl_sleep(POLLING_TIME);

		if ((error = rwl_var_getbuf(wl, cmdname, NULL, 0, &pkt_ptr)) < 0) {
			DPRINT_ERR(ERR, "No packet in wl driver\r\n");
			return BCME_ERROR;
		}

		DPRINT_DBG(OUTPUT, "Polling the wl driver, error status=%d\n", error);

		if ((*(int *)pkt_ptr) == 0) {
			DPRINT_DBG(ERR, "packet not received\n");
			return BCME_ERROR;
		}

		DPRINT_DBG(OUTPUT, "packet received\n");

		/* Extract CDC header in order to determine buffer requirements */
		memcpy(g_rem_pkt_ptr, pkt_ptr, sizeof(rem_packet_t));
		g_rem_ptr = &g_rem_pkt_ptr->rem_cdc;
	}
#endif /* RWL_DONGLE */

#ifdef RWL_SERIAL
	{
		if (g_rwl_hndle == -1) {
			DPRINT_ERR(ERR, "failed to open com port.\r\n");
			return BCME_ERROR;
		}

		if ((g_rem_ptr = remote_CDC_rx_hdr((void *)&g_rwl_hndle, 1)) == NULL) {
			DPRINT_DBG(OUTPUT, "\n Waiting for client to transmit command\n");
			return BCME_ERROR;
		}
	}
#endif  /* RWL_SERIAL */

#ifdef RWL_WIFI
	{
		/* Poll the driver for the valid action frame and update the CDC + data  */
		dot11_action_wifi_vendor_specific_t *list;

		if ((list = rwl_wifi_allocate_actionframe()) == NULL) {
			DPRINT_DBG(OUTPUT, "remote_rx_header: Failed to allocate frame \n");
			return BCME_ERROR;
		}

		if (remote_CDC_DATA_wifi_rx((void *)wl, list) < 0) {
			free(list);
			return BCME_ERROR;
		}

		/* copy the valid length of the data to the g_rem_pkt_ptr */
		memcpy(g_rem_pkt_ptr, &list->data[0], sizeof(rem_packet_t));
		g_rem_ptr = &g_rem_pkt_ptr->rem_cdc;
		free(list);
	}
#endif /* RWL_WIFI */

	rwl_swap_header(g_rem_ptr, NETWORK_TO_HOST);

	DPRINT_INFO(OUTPUT, "%d %d %d %d\r\n", g_rem_ptr->msg.cmd,
	g_rem_ptr->msg.len, g_rem_ptr->msg.flags, g_rem_ptr->data_len);

	return SUCCESS;

}