/* * 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 { rwl_sleep(RWL_WIFI_RX_DELAY); } } /* If failed to get the valid frame , indicate the error */ if (!(rec_frame->category == RWL_ACTION_WIFI_CATEGORY)) { return (FAIL); } 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_setbuf(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; }
void rwl_sync_delay(uint noframes) { if (noframes > 1) { rwl_sleep(LINUX_SYNC_DELAY); } }
/* * 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 = 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 */ err = (int)ir_setinformation(wl, wifi_cmds[count].cmd + WL_OID_BASE, bigbuf, &len); #endif 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); rwl_sleep(INIT_CMD_SLEEP); } }
void rwl_sync_delay(unsigned int noframes) { if (noframes > 1) { rwl_sleep(200); } }
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); rem_ptr->msg.cmd = cmd; rem_ptr->msg.len = buf_len; rem_ptr->msg.flags = flags; rem_ptr->data_len = data_len; 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 (rem_ptr->msg.len > RWL_WIFI_FRAG_DATA_SIZE) { /* response needs to be sent in fragments */ totalframes = rem_ptr->msg.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_setbuf(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_setbuf(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) != rem_ptr->msg.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], (rem_ptr->msg.len - (tx_count*RWL_WIFI_FRAG_DATA_SIZE))); if ((error = rwl_var_setbuf(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_setbuf(wl, RWL_WIFI_ACTION_CMD, rem_wifi_send, RWL_WIFI_ACTION_FRAME_SIZE); free(rem_wifi_send); return error; } } #endif /* RWL_WIFI */ return (0); }
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; /* 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 = strlen((char*)loc_buf); DPRINT_DBG(OUTPUT, "rwl %x %d %d %d ", rem_ptr->msg.cmd, rem_ptr->msg.len, rem_ptr->msg.flags, rem_ptr->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", rem_ptr->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 (rem_ptr->msg.len); /* Return size of actual buffer to satisfy accounting going on above this level */ }
/* * 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; 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; 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(&rem_wifi_send->data[RWL_REF_MAC_ADDRESS_OFFSET], &id[0], 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++) { 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_setbuf(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_WIFI_RETRY_DELAY); 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); } /* 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_WIFI_RETRY_DELAY); } free(rem_wifi_send); free(rem_wifi_recv); 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; }
/* transport independent entry point for GET ioctls */ int rwl_queryinformation_fe(void *wl, int cmd, void* input_buf, unsigned long *input_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 int retry; char *cinput_buf; #endif UNUSED_PARAMETER(debug); switch (remote_type) { case REMOTE_SOCKET: #ifdef RWL_SOCKET /* We don't want the server to allocate bigger buffers * for some of the commands * like scanresults. Server can still allocate 8K memory * and send the response */ if ((int)(*input_len) > SERVER_RESPONSE_MAX_BUF_LEN) *input_len = SERVER_RESPONSE_MAX_BUF_LEN; error = rwl_information_socket(wl, cmd, input_buf, input_len, input_len, rem_ioctl_select); #endif /* RWL_SOCKET */ break; #ifdef RWL_SERIAL /* System serial transport is not supported in Linux. Only XP */ case REMOTE_SERIAL: tx_len = MIN(*input_len, SERVER_RESPONSE_MAX_BUF_LEN); if (remote_CDC_tx(wl, cmd, input_buf, tx_len, tx_len, rem_ioctl_select, debug) < 0) { DPRINT_ERR(ERR, "query_info_fe: Send command failed\n"); return FAIL; } if ((rem_ptr = remote_CDC_rx_hdr(wl, debug)) == NULL) { DPRINT_ERR(ERR, "query_info_fe: Reading CDC header failed\n"); return FAIL; } if (rem_ptr->msg.flags != REMOTE_REPLY) { DPRINT_ERR(ERR, "query_info_fe: response format error.\n"); return FAIL; } if (rem_ptr->msg.len > *input_len) { DPRINT_ERR(ERR, "query_info_fe: needed size(%d) greater than " "actual size(%lu)\n", rem_ptr->msg.len, *input_len); return FAIL; } error = rem_ptr->msg.status; if (error != 0) DPRINT_ERR(ERR, "query_info_fe: remote cdc header return " "error code %d\n", error); if (remote_CDC_rx(wl, rem_ptr, input_buf, *input_len, debug) == -1) { DPRINT_ERR(ERR, "query_info_fe: No results!\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: /* We don't want the server to allocate bigger buffers * for some of the commands * like scanresults. Server can still allocate 8K *memory and send the response * in fragments. */ if ((int)(*input_len) > SERVER_RESPONSE_MAX_BUF_LEN) *input_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(*input_len, 256); error = rwl_information_dongle(wl, cmd, input_buf, input_len, tx_len, rem_ioctl_select); break; #endif //ifdef RWL_DONGLE case REMOTE_WIFI: #ifdef RWL_WIFI /* We don't want the server to allocate bigger buffers * for some of the commands * like scanresults. Server can still allocate 8K memory * and send the response * in fragments. */ if ((int)(*input_len) > SERVER_RESPONSE_MAX_BUF_LEN) *input_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(*input_len, RWL_WIFI_FRAG_DATA_SIZE); if ((rem_ptr = (rem_ioctl_t *)malloc(REMOTE_SIZE)) == NULL) { return FAIL; } if ((cinput_buf = (char*)malloc(tx_len)) == NULL) { DPRINT_ERR(ERR, "Malloc failed for query information fe" "character buf \n"); free(rem_ptr); return FAIL; } memcpy(cinput_buf, (char*)input_buf, tx_len); /* Keep a copy of input_buf */ for (retry = 0; retry < RWL_WIFI_RETRY; retry++) { rwl_wifi_purge_actionframes(wl); if (retry > 3) DPRINT_INFO(OUTPUT, "ir_queryinformation_fe : retry %d" "cmd %d\n", retry, cmd); /* copy back the buffer to input buffer */ memcpy((char*)input_buf, cinput_buf, tx_len); /* Issue the command */ if ((error = remote_CDC_wifi_tx(wl, cmd, input_buf, *input_len, tx_len, rem_ioctl_select)) < 0) { DPRINT_DBG(OUTPUT, "query_info_fe: Send command failed\n"); rwl_sleep(RWL_WIFI_RETRY_DELAY); continue; } if ((error = remote_CDC_DATA_wifi_rx_frag(wl, rem_ptr, *input_len, input_buf, RWL_WIFI_WL_CMD) < 0)) { DPRINT_DBG(OUTPUT, "ir_queryinformation_fe :" "Error in reading the frag bytes\n"); rwl_sleep(RWL_WIFI_RETRY_DELAY); continue; } if (rem_ptr->msg.flags & REMOTE_REPLY) { error = rem_ptr->msg.cmd; break; } else { rwl_sleep(RWL_WIFI_RETRY_DELAY); } } free(rem_ptr); if (cinput_buf) free(cinput_buf); break; #endif /* RWL_WIFI */ default: DPRINT_ERR(ERR, "rwl_queryinformation_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; }
/* 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; }