| /* |
| * File Name: wlu_server_shared.c |
| * Common server specific functions for linux and win32 |
| * |
| * 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_server_shared.c 570087 2015-07-09 22:10:06Z $ |
| */ |
| |
| /* |
| * Description: Main Server specific wrappers |
| * This module implements all the server specific functions |
| * for Win32 and Linux |
| */ |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <ctype.h> |
| #ifdef TARGETOS_symbian |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| #include <sys/time.h> |
| |
| #else |
| #if !defined(TARGETOS_nucleus) |
| #include <malloc.h> |
| #endif |
| #endif /* TARGETOS_symbian */ |
| #include <assert.h> |
| |
| #include <errno.h> |
| #ifndef WIN32 |
| #if !defined(TARGETOS_nucleus) |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| #if !defined(TARGETOS_symbian) |
| #include <arpa/inet.h> |
| #include <net/if.h> |
| #endif |
| #include <unistd.h> |
| #include <netdb.h> |
| #include <signal.h> |
| #endif /* TARGETOS_nucleus */ |
| #endif /* WIN32 */ |
| |
| #ifdef WIN32 |
| #include <windows.h> |
| #include <winioctl.h> |
| #include <ntddndis.h> |
| #include <typedefs.h> |
| #include <epictrl.h> |
| #include <irelay.h> |
| #include <proto/ethernet.h> |
| #include <nuiouser.h> |
| #include <bcmendian.h> |
| #include <oidencap.h> |
| #include <bcmutils.h> |
| #include <proto/802.11.h> |
| #endif /* WIN32 */ |
| |
| #include <bcmcdc.h> |
| #include <wlioctl.h> |
| #include <typedefs.h> |
| #include <bcmendian.h> |
| #include <bcmutils.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" |
| #include "wlu_pipe.h" |
| #include "wlu_server_shared.h" |
| #ifdef RWLASD |
| extern int g_serv_sock_desc; |
| #endif |
| int g_rwl_hndle; |
| int set_ctrlc = 0; |
| |
| #ifdef RWL_DONGLE |
| static rem_ioctl_t loc_cdc; |
| static const char* cmdname = "remote"; |
| static const char* dongleset = "dongleset"; |
| #endif |
| |
| #if defined(LINUX) |
| extern void store_old_interface(void *wl, char *old_intf_name); |
| extern int wl_check(void *wl); |
| #endif /* defined(LINUX) */ |
| |
| extern void handle_ctrlc(int unused); |
| /* Function: rwl_transport_setup |
| * This will do the initialization for |
| * for all the transports |
| */ |
| static int |
| rwl_transport_setup(int argc, char** argv) |
| { |
| int transport_descriptor = -1; |
| |
| UNUSED_PARAMETER(argc); |
| UNUSED_PARAMETER(argv); |
| |
| #ifdef RWL_SOCKET |
| /* This function will parse the socket command line arguments |
| * & open the socket in listen mode |
| */ |
| remote_type = REMOTE_SOCKET; |
| transport_descriptor = rwl_init_server_socket_setup(argc, argv, remote_type); |
| |
| if (transport_descriptor < 0) { |
| DPRINT_ERR(ERR, "wl_socket_server:Transport setup failed \n"); |
| } |
| #endif /* RWL_SOCKET */ |
| #if defined(RWL_DONGLE) || defined(RWL_WIFI) || defined(RWL_SERIAL) |
| g_rem_pkt_ptr = &g_rem_pkt; |
| transport_descriptor = 0; |
| |
| #ifdef RWL_WIFI |
| remote_type = REMOTE_WIFI; |
| #endif |
| |
| #ifdef RWL_DONGLE |
| remote_type = REMOTE_DONGLE; |
| #endif /* RWL_DONGLE */ |
| #ifdef RWL_SERIAL |
| remote_type = REMOTE_SERIAL; |
| if (argc < 2) { |
| DPRINT_ERR(ERR, "Port name is required from the command line\n"); |
| } else { |
| (void)*argv++; |
| DPRINT_DBG(OUTPUT, "Port name is %s\n", *argv); |
| transport_descriptor = *(int*) rwl_open_transport(remote_type, *argv, 0, 0); |
| } |
| #endif /* RWL_SERIAL */ |
| #endif /* RWL_DONGLE ||RWL_SERIAL ||RWL_WIFI */ |
| #ifdef RWLASD |
| g_serv_sock_desc = transport_descriptor; |
| #endif |
| return transport_descriptor; |
| |
| } |
| |
| /* 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; |
| size_t cdc_and_actionframe_copy_length; |
| |
| 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 */ |
| cdc_and_actionframe_copy_length = sizeof(rem_packet_t) > sizeof(list->data[0])? |
| sizeof(list->data[0]): sizeof(rem_packet_t); |
| memcpy(g_rem_pkt_ptr, &list->data[0], cdc_and_actionframe_copy_length); |
| 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; |
| |
| } |
| |
| /* Function: remote_rx_data |
| * This function will receive the data from client |
| * for different transports |
| * In case of socket the data comes from a open TCP socket |
| * However in case of dongle UART or wi-fi the data is accessed |
| * from the driver buffers. |
| */ |
| int |
| remote_rx_data(void* buf_ptr) |
| { |
| #if defined(RWL_SOCKET) || defined(RWL_SERIAL) |
| |
| if ((remote_CDC_rx((void *)&g_rwl_hndle, g_rem_ptr, buf_ptr, |
| g_rem_ptr->msg.len, 0)) == BCME_ERROR) { |
| DPRINT_ERR(ERR, "Reading CDC %d data bytes failed\n", g_rem_ptr->msg.len); |
| return BCME_ERROR; |
| } |
| #elif defined(RWL_DONGLE) || defined(RWL_WIFI) |
| if (g_rem_ptr->data_len != 0) { |
| int length = g_rem_ptr->data_len; |
| if (g_rem_ptr->data_len > g_rem_ptr->msg.len) { |
| length = g_rem_ptr->msg.len; |
| } |
| memcpy(buf_ptr, g_rem_pkt_ptr->message, length); |
| } |
| else |
| buf_ptr = NULL; |
| #else |
| UNUSED_PARAMETER(buf_ptr); |
| #endif /* RWL_SOCKET || RWL_SERIAL */ |
| return SUCCESS; |
| } |
| |
| #ifdef RWL_DONGLE |
| /* |
| * Function to send the serial response to wl driver |
| * The function calculates the no of frames based on the DATA_FRAME_LEN |
| * adds cdc header to every frame, copies the header and fragmented frame |
| * into rem_buf_ptr and sends the packet down to wl driver |
| */ |
| |
| static int |
| rwl_serial_fragmented_tx(void* wl, rem_ioctl_t *rem_ptr, uchar *buf_ptr, int error) |
| { |
| rem_ioctl_t *loc_ptr = &loc_cdc; |
| uchar* rem_buf_ptr; |
| uint noframes = 1; /* Default noframes = 1 */ |
| uint count; |
| uint frame_count; |
| uint rem_bytes; |
| |
| loc_ptr->msg.cmd = error; |
| loc_ptr->msg.flags = REMOTE_REPLY; |
| loc_ptr->msg.len = rem_ptr->msg.len; |
| loc_ptr->data_len = rem_ptr->data_len; |
| |
| /* Fragment the result if it is more than DATA_FRAME_LEN (960) */ |
| if (loc_ptr->msg.len > DATA_FRAME_LEN) { |
| /* Calculate no of frames */ |
| noframes = (loc_ptr->msg.len)/DATA_FRAME_LEN; |
| if ((loc_ptr->msg.len) % DATA_FRAME_LEN > 0) { |
| noframes += 1; |
| rem_bytes = (loc_ptr->msg.len) % DATA_FRAME_LEN; |
| } else { |
| rem_bytes = DATA_FRAME_LEN; |
| } |
| } else { |
| rem_bytes = loc_ptr->msg.len; |
| } |
| DPRINT_INFO(OUTPUT, "No of frames = %d, rem_bytes:%d\n", noframes, rem_bytes); |
| count = 0; |
| frame_count = noframes; |
| rem_buf_ptr = (uchar*)malloc(DONGLE_TX_FRAME_SIZE + REMOTE_SIZE); |
| |
| while (count < noframes) { |
| memset(rem_buf_ptr, 0, DONGLE_TX_FRAME_SIZE + REMOTE_SIZE); |
| /* Send reply to client */ |
| rem_ptr->msg.cmd = loc_ptr->msg.cmd; |
| rem_ptr->msg.flags = loc_ptr->msg.flags; |
| rem_ptr->msg.len = loc_ptr->msg.len; |
| |
| if (frame_count == 1) |
| rem_ptr->data_len = rem_bytes; |
| else |
| rem_ptr->data_len = DATA_FRAME_LEN; |
| |
| DPRINT_DBG(OUTPUT, "GET--rem_ptr->data_len=%d\n", rem_ptr->data_len); |
| |
| /* Copy CDC Header */ |
| memcpy(rem_buf_ptr, (uchar*)rem_ptr, REMOTE_SIZE); |
| |
| /* Copy Data now */ |
| memcpy(&rem_buf_ptr[REMOTE_SIZE], &buf_ptr[count*DATA_FRAME_LEN], |
| rem_ptr->data_len); |
| count++; |
| frame_count--; |
| |
| DPRINT_INFO(OUTPUT, "FRAME %d\n", count); |
| DPRINT_INFO(OUTPUT, "%d %d %d %d\n", rem_ptr->msg.cmd, rem_ptr->msg.len, |
| rem_ptr->msg.flags, rem_ptr->data_len); |
| |
| rwl_sync_delay(noframes); |
| |
| if ((error = rwl_var_setbuf(wl, cmdname, rem_buf_ptr, |
| DONGLE_TX_FRAME_SIZE+REMOTE_SIZE)) < 0) { |
| DPRINT_INFO(OUTPUT, "Unable to send to wl driver,error=%d\n", error); |
| if (rem_buf_ptr) |
| free(rem_buf_ptr); |
| return BCME_ERROR; |
| } |
| else |
| DPRINT_INFO(OUTPUT, "Packet sent to wl driver,error=%d\n", error); |
| } |
| |
| if (rem_buf_ptr) |
| free(rem_buf_ptr); |
| |
| return error; |
| } |
| |
| /* This function transmits the response to the dongle driver in the case |
| * of serial dongle transport. |
| * In the case of big response, it calls the rwl_serial_fragmented_response |
| * function to fragment the response and sends down to the driver. |
| */ |
| |
| static int |
| remote_CDC_dongle_tx(void *wl, uint cmd, uchar *buf, uint buf_len, uint data_len, uint flags) |
| { |
| int error; |
| rem_ioctl_t resp_rem_cdc; |
| |
| if (flags & REMOTE_SET_IOCTL) { |
| uchar* rem_buf_ptr; |
| /* for set commands message length and data length should be set to zero |
| * unlike Get Ioctl which will have valid data and message length |
| */ |
| resp_rem_cdc.msg.len = 0; |
| resp_rem_cdc.data_len = 0; |
| resp_rem_cdc.msg.cmd = cmd; |
| resp_rem_cdc.msg.flags = REMOTE_REPLY; |
| |
| DPRINT_INFO(OUTPUT, "Set:Resp packet:%d %d %d %d\n", resp_rem_cdc.msg.cmd, |
| resp_rem_cdc.msg.len, resp_rem_cdc.msg.flags, resp_rem_cdc.data_len); |
| |
| if ((rem_buf_ptr = (uchar*)malloc(DONGLE_TX_FRAME_SIZE + REMOTE_SIZE)) == NULL) { |
| DPRINT_ERR(ERR, "malloc failed for remote_CDC_dongle_tx\n"); |
| return BCME_ERROR; |
| } |
| |
| /* Send reply to client here */ |
| memcpy(rem_buf_ptr, (char*)(&resp_rem_cdc), REMOTE_SIZE); |
| if ((error = rwl_var_setbuf((void*)wl, cmdname, rem_buf_ptr, |
| DONGLE_TX_FRAME_SIZE + REMOTE_SIZE)) < 0) { |
| DPRINT_ERR(ERR, "unable to send SET results to driver=%d\n", error); |
| } else |
| DPRINT_INFO(OUTPUT, "Packet sent to wl driver, error=%d\n", error); |
| |
| if (rem_buf_ptr) |
| free(rem_buf_ptr); |
| |
| } else { /* GET_IOCTL */ |
| resp_rem_cdc.msg.cmd = cmd; |
| resp_rem_cdc.msg.len = buf_len; |
| resp_rem_cdc.msg.flags = flags; |
| resp_rem_cdc.data_len = data_len; |
| if ((error = rwl_serial_fragmented_tx(wl, &resp_rem_cdc, buf, cmd)) < 0) |
| DPRINT_ERR(ERR, "wl_server_serial: Return error code failed\n"); |
| } |
| return error; |
| } |
| #endif /* RWL_DONGLE */ |
| |
| /* This function gets the command send by the client from the dongle driver */ |
| int |
| rwl_var_getbuf(void* wl, const char* iovar, void* param, int param_len, void** buf_ptr) |
| { |
| int len; |
| |
| memset(rwl_buf, 0, WLC_IOCTL_MAXLEN); |
| strcpy((char*)rwl_buf, iovar); |
| /* include the null */ |
| len = strlen(iovar) + 1; |
| |
| if (param_len) |
| memcpy(&rwl_buf[len], param, param_len); |
| |
| *buf_ptr = rwl_buf; |
| |
| return wl_get(wl, WLC_GET_VAR, &rwl_buf[0], WLC_IOCTL_MAXLEN); |
| } |
| |
| /* This function will send the buffer to the dongle driver */ |
| int |
| rwl_var_setbuf(void* wl, const char* iovar, void* param, int param_len) |
| { |
| int len; |
| |
| memset(rwl_buf, 0, WLC_IOCTL_MAXLEN); |
| strcpy((char*)rwl_buf, iovar); |
| |
| /* include the null */ |
| len = strlen(iovar) + 1; |
| |
| if (param_len) |
| memcpy(&rwl_buf[len], param, param_len); |
| |
| len += param_len; |
| |
| DPRINT_DBG(OUTPUT, "setbuf:%s, len:%d\n", rwl_buf, len); |
| |
| return wl_set(wl, WLC_SET_VAR, &rwl_buf[0], len); |
| } |
| |
| /* This function will send the buffer to the dongle driver */ |
| int |
| rwl_var_send_vs_actionframe(void* wl, const char* iovar, void* param, int param_len) |
| { |
| int len; |
| |
| memset(rwl_buf, 0, WLC_IOCTL_MAXLEN); |
| strcpy((char*) rwl_buf, iovar); |
| |
| /* include the null */ |
| len = strlen(iovar) + 1; |
| |
| if (param_len) |
| memcpy((void*)&rwl_buf[len+ OFFSETOF(wl_action_frame_t, data)], param, param_len); |
| |
| /* Set the PacketID (not used by remote WL */ |
| memset((void*)&rwl_buf[len + OFFSETOF(wl_action_frame_t, packetId)], 0, 4); |
| |
| /* Set the dest addr */ |
| memcpy((void*)&rwl_buf[len + OFFSETOF(wl_action_frame_t, da)], |
| (void*)&rwlea, |
| ETHER_ADDR_LEN); |
| |
| /* set the length */ |
| memcpy((void*)&rwl_buf[len + OFFSETOF(wl_action_frame_t, len)], (void*) ¶m_len, 2); |
| |
| len += param_len + ETHER_ADDR_LEN + 2 + 4; |
| |
| DPRINT_DBG(OUTPUT, "setbuf:%s, len:%d\n", rwl_buf, len); |
| |
| return wl_set(wl, WLC_SET_VAR, &rwl_buf[0], len); |
| } |
| /* |
| * This function is used for transmitting the response over different |
| * transports. |
| * In case of socket the data is directly sent to the client which is waiting on a open socket. |
| * In case of socket the data is sent in one big chunk unlike other transports |
| * |
| * In case of serial the data is sent to the driver using remote_CDC_dongle_tx function |
| * which in turn may fragment the data and send it in chunks to the client. |
| * |
| * In case of wi-fi the data is sent to the driver using the remote_CDC_tx. However |
| * in this case the data is converted into 802.11 Action frames and sent using wi-fi driver. |
| * Arguments: wl - Driver handle |
| * hndle - Socket handle for socket transport. |
| */ |
| int |
| remote_tx_response(void *wl, void* buf_ptr, int cmd) |
| { |
| int error = -1; |
| |
| UNUSED_PARAMETER(wl); |
| UNUSED_PARAMETER(buf_ptr); |
| UNUSED_PARAMETER(cmd); |
| |
| #if defined(RWL_SOCKET) || defined(RWL_SERIAL) |
| if ((error = remote_CDC_tx((void*)&g_rwl_hndle, cmd, buf_ptr, g_rem_ptr->msg.len, |
| g_rem_ptr->msg.len, REMOTE_REPLY, 0)) < 0) |
| DPRINT_ERR(ERR, "wl_server: Return results failed\n"); |
| #endif /* RWL_SOCKET || RWL_SERIAL */ |
| |
| #ifdef RWL_DONGLE |
| if ((error = remote_CDC_dongle_tx(wl, cmd, buf_ptr, g_rem_ptr->msg.len, |
| g_rem_ptr->data_len, g_rem_ptr->msg.flags)) < 0) |
| DPRINT_ERR(ERR, "wl_server: Return results failed\n"); |
| #endif /* RWL_DONGLE */ |
| |
| #ifdef RWL_WIFI |
| /* Purge all the queued cmd's , this to ensure late response time out at */ |
| /* client side and client might issue the next cmd if server is slow */ |
| if ((error = rwl_wifi_purge_actionframes(wl)) < 0) |
| return error; |
| if ((g_rem_ptr->msg.flags & REMOTE_SHELL_CMD) || |
| (g_rem_ptr->msg.flags & REMOTE_GET_IOCTL)|| |
| (g_rem_ptr->msg.flags & REMOTE_ASD_CMD) || |
| (g_rem_ptr->msg.flags & REMOTE_VISTA_CMD)) { |
| if ((error = remote_CDC_tx(wl, cmd, buf_ptr, g_rem_ptr->msg.len, |
| g_rem_ptr->msg.len, REMOTE_REPLY, 0)) < 0) |
| DPRINT_ERR(ERR, "Wifi_server: Return results failed\n"); |
| } else { |
| if ((error = remote_CDC_tx(wl, cmd, buf_ptr, 0, 0, REMOTE_REPLY, 0)) < 0) |
| DPRINT_ERR(ERR, "Failed due to bad flag %d\n", g_rem_ptr->msg.flags); |
| } |
| #endif /* RWL_WIFI */ |
| return error; |
| } |
| |
| /* Close the Socket handle */ |
| void close_sock_handle(int hndle) |
| { |
| #ifdef RWL_SOCKET |
| rwl_close_pipe(remote_type, (void*)&hndle); |
| #else |
| UNUSED_PARAMETER(hndle); |
| #endif |
| } |
| |
| |
| /* |
| * Send the response to the remote if the channel of the server matches with the |
| * server channel. |
| */ |
| void remote_wifi_response(void* wl) |
| { |
| #ifdef RWL_WIFI |
| dot11_action_wifi_vendor_specific_t *list; |
| |
| if ((list = rwl_wifi_allocate_actionframe()) == NULL) { |
| DPRINT_DBG(OUTPUT, "remote_wifi_response: Failed to allocate frame \n"); |
| return; |
| } |
| |
| /* it's sync frame and received from client */ |
| memcpy((char*)&list->data[RWL_WIFI_CDC_HEADER_OFFSET], |
| &g_rem_pkt_ptr[RWL_WIFI_CDC_HEADER_OFFSET], REMOTE_SIZE); |
| memcpy((char*)&list->data[REMOTE_SIZE], g_rem_pkt_ptr->message, |
| RWL_WIFI_FRAG_DATA_SIZE); |
| list->type = RWL_WIFI_FIND_MY_PEER; |
| /* Store the client mac addr */ |
| memcpy((void*)&rwlea, (void*)&list->data[RWL_DUT_MAC_ADDRESS_OFFSET], ETHER_ADDR_LEN); |
| /* send the response to client if server is on the same channel */ |
| rwl_wifi_find_server_response(wl, list); |
| |
| free(list); |
| #else |
| UNUSED_PARAMETER(wl); |
| #endif /* RWL_WIFI */ |
| return; |
| } |
| |
| /* Function to check IN-dongle mode firmware */ |
| int |
| rwl_iovar_check(void *wl) |
| { |
| void *ptr; |
| #ifdef RWL_WIFI |
| dot11_action_wifi_vendor_specific_t rec_frame; |
| |
| /* Check for indongle mode firmware */ |
| return rwl_var_getbuf(wl, RWL_WIFI_GET_ACTION_CMD, &rec_frame, |
| RWL_WIFI_ACTION_FRAME_SIZE, &ptr); |
| #endif |
| UNUSED_PARAMETER(ptr); |
| UNUSED_PARAMETER(wl); |
| #ifdef RWL_DONGLE |
| return rwl_var_getbuf(wl, "remote", NULL, 0, &ptr); |
| #else |
| return 0; |
| #endif |
| } |
| |
| |
| #ifndef TARGETOS_symbian |
| /* Function to get a ctrl-c packet */ |
| int |
| get_ctrlc_header(void *wl) |
| { |
| #if defined(RWL_SOCKET) || defined(RWL_SERIAL) |
| fd_set fdset; |
| struct timeval tv; |
| UNUSED_PARAMETER(wl); |
| FD_ZERO(&fdset); |
| FD_SET((unsigned)g_rwl_hndle, &fdset); |
| tv.tv_sec = 0; |
| tv.tv_usec = 0; |
| if ((select(g_rwl_hndle+1, &fdset, NULL, NULL, &tv)) > 0) { |
| if (FD_ISSET(g_rwl_hndle, &fdset)) { |
| remote_CDC_rx_hdr((void *)&g_rwl_hndle, 0); |
| return BCME_OK; |
| } |
| } |
| return BCME_ERROR; |
| |
| #else |
| return remote_rx_header(wl, 0); |
| #endif /* if defined(RWL_SOCKET) || defined(RWL_SERIAL) */ |
| } |
| #endif /* TARGETOS_symbian */ |
| |
| /* Main server module common for all transports |
| * This module will do the initial transport setups. |
| * Then it receives the command from client in CDC format |
| * and transmits the response back to the client. |
| * In the case of socket, it receives the command from the client |
| * and sends the response directly to the client via TCP socket. |
| * |
| * In the case of serial & wifi , it receives the command from the driver |
| * and sends the response to the driver. |
| */ |
| #if defined(PCIE_MFGTEST) |
| char *fw_download_path = "/tmp/media/nand/rtecdc.bin"; |
| char *nvram_download_path = "/tmp/media/nand/nvram.txt"; |
| #endif |
| int |
| remote_server_exec(int argc, char **argv, void *wl) |
| { |
| int err; |
| int transport_descriptor; |
| char *async_cmd_flag = NULL; |
| int skip; |
| int download_flag = 0; |
| FILE *fp = NULL; |
| #if defined(PCIE_MFGTEST) |
| char *fn = fw_download_path; |
| char *fw = nvram_download_path; |
| #else |
| char *fn = "dwnldfile.bin"; |
| char *fw = "nvram.txt"; |
| #endif |
| |
| #if defined(LINUX) || defined(OLYMPIC_RWL) |
| char old_intf_name[IFNAMSIZ]; |
| #endif |
| #ifdef WIN32 |
| char shell_fname[MAX_SHELL_FILE_LENGTH]; |
| DWORD dwlen; |
| #endif |
| #ifdef RWL_DONGLE |
| int uart_enable = 1; |
| /* To set dongle flag when dongle server starts */ |
| if ((err = rwl_var_setbuf(wl, dongleset, &uart_enable, |
| sizeof(int))) < 0) { |
| DPRINT_INFO(OUTPUT, "Unable to send to wl driver,error=%d\n", err); |
| } |
| #endif |
| if (rwl_iovar_check (wl) < 0) { |
| DPRINT_ERR(ERR, "wl_server: RWL_WIFI/RWL_DONGLE not defined "); |
| DPRINT_ERR(ERR, "Or In-Dongle mode enabled\n"); |
| exit(0); |
| } |
| /* Initialise for all the transports - socket, serial, and wifi |
| * In Socket transport, main socket handler will be returned. |
| */ |
| if ((transport_descriptor = rwl_transport_setup(argc, argv)) < 0) |
| return BCME_ERROR; |
| |
| #ifdef RWL_WIFI |
| remote_wifi_ser_init_cmds(wl); |
| #endif |
| /* Create a directory /tmp/RWL for the shell response files */ |
| if (rwl_create_dir() < 0) |
| return BCME_ERROR; |
| |
| |
| #ifdef RWLASD |
| /* DUT initialization function */ |
| wfa_dut_init(&trafficBuf, &respBuf, &parmsVal, &xcCmdBuf, &toutvalp); |
| #endif |
| |
| #if defined(LINUX) |
| /* Copy old interface name to restore it */ |
| store_old_interface(wl, old_intf_name); |
| #endif /* defined(LINUX) */ |
| |
| while (1) { |
| uchar *buf_ptr = NULL; |
| #if defined(LINUX) |
| char *errstr = NULL; |
| #endif |
| #ifdef VISTA_SERVER |
| int index; |
| char *vista_buf[MAX_VISTA_ARGC]; |
| #endif |
| #ifdef RWL_SERIAL |
| g_rwl_hndle = transport_descriptor; |
| #else |
| g_rwl_hndle = -1; |
| #endif |
| #ifdef RWL_DONGLE |
| if (set_ctrlc) { |
| uart_enable = 0; |
| if ((err = rwl_var_setbuf(wl, dongleset, &uart_enable, |
| sizeof(int))) < 0) { |
| DPRINT_INFO(OUTPUT, "Unable to send to wl driver,error=%d\n", err); |
| } |
| set_ctrlc = 0; |
| exit(0); |
| } |
| #endif /* RWL_DONGLE */ |
| |
| /* Receive the CDC header */ |
| if ((remote_rx_header(wl, transport_descriptor)) == BCME_ERROR) { |
| DPRINT_DBG(OUTPUT, "\n Waiting for client to transmit command\n"); |
| continue; |
| } |
| |
| DPRINT_INFO(OUTPUT, "REC : cmd %d\t msg len %d msg flag %d\t msg status %d\n", |
| g_rem_ptr->msg.cmd, g_rem_ptr->msg.len, |
| g_rem_ptr->msg.flags, g_rem_ptr->msg.status); |
| |
| #ifdef RWL_WIFI |
| /* send the response to remote if it is findserver cmd, this is specific to wifi */ |
| if (g_rem_ptr->msg.flags & REMOTE_FINDSERVER_IOCTL) { |
| remote_wifi_response(wl); |
| continue; |
| } |
| #endif /* RWL_WIFI */ |
| |
| /* |
| * Allocate buffer only if there is a response message expected. |
| * Some commands such as up/down do not output anything. |
| */ |
| if (g_rem_ptr->msg.len) { |
| if ((buf_ptr = malloc(g_rem_ptr->msg.len)) == NULL) { |
| DPRINT_ERR(ERR, "malloc of %d bytes failed\n", g_rem_ptr->msg.len); |
| continue; |
| } |
| } |
| |
| /* Receive the data */ |
| if ((err = remote_rx_data(buf_ptr)) == BCME_ERROR) { |
| if (buf_ptr) |
| free(buf_ptr); |
| continue; |
| } |
| |
| /* Process RWL negotiate commands */ |
| if (g_rem_ptr->msg.flags & REMOTE_NEGOTIATE_CMD) { |
| if (g_rem_ptr->msg.cmd == NEGOTIATE_GET_OS) { |
| if (g_rem_ptr->msg.len >= sizeof(int)) { |
| #if defined(LINUX) |
| *(int*)buf_ptr = LINUX_OS; |
| #elif defined(VISTA_SERVER) |
| *(int*)buf_ptr = WINVISTA_OS; |
| #elif defined(WIN32) |
| *(int*)buf_ptr = WIN32_OS; |
| #else |
| *(int*)buf_ptr = UNKNOWN_OS; |
| #endif |
| g_rem_ptr->msg.len = sizeof(int); |
| |
| DPRINT_INFO(OUTPUT, "RESP : os type %d\n", *(int*)buf_ptr); |
| if (remote_tx_response(wl, buf_ptr, 0) < 0) |
| DPRINT_ERR(ERR, "\nReturn results failed\n"); |
| } |
| } |
| #ifdef RWL_SOCKET |
| close_sock_handle(g_rwl_hndle); |
| #endif /* RWL_SOCKET */ |
| if (buf_ptr) |
| free(buf_ptr); |
| continue; |
| } |
| |
| /* Process command */ |
| if (g_rem_ptr->msg.flags & REMOTE_SHELL_CMD) { |
| /* Get the response length first and get the response buffer in case of |
| * synchronous shell commands and the buf_ptr will have the response file |
| * name. In case of asynchronous shell commands, buf_ptr |
| * will be get updated by the remote_shell_execute function. |
| */ |
| need_speedy_response = 1; |
| #ifndef WIN32 |
| if (buf_ptr) { |
| async_cmd_flag = strstr((char*)buf_ptr, "%"); |
| } |
| if ((err = remote_shell_execute((char*)buf_ptr, wl)) > 0) { |
| if (async_cmd_flag) |
| g_rem_ptr->msg.len = err; |
| } |
| /* Sync shell command: No need to send response from here */ |
| else { |
| #ifdef RWL_SOCKET |
| /* Transmitted to client. Then close the handle & |
| * get the new handle for next transmission & reception. |
| */ |
| close_sock_handle(g_rwl_hndle); |
| #endif /* RWL_SOCKET */ |
| continue; |
| } |
| #else |
| if ((err = remote_shell_execute((char*)buf_ptr, wl)) != SUCCESS) { |
| DPRINT_ERR(ERR, "Error in executing shell command\n"); |
| if (buf_ptr) |
| free(buf_ptr); |
| #ifdef RWL_SOCKET |
| /* Transmitted to client. Then close the handle & |
| * get the new handle for next transmission & reception. |
| */ |
| close_sock_handle(g_rwl_hndle); |
| #endif /* RWL_SOCKET */ |
| continue; |
| } |
| /* Get the response from the temporary file */ |
| if ((err = remote_shell_get_resp(shell_fname, wl)) != SUCCESS) { |
| DPRINT_ERR(ERR, "Error in executing shell command\n"); |
| } |
| if (buf_ptr) |
| free(buf_ptr); |
| #ifdef RWL_SOCKET |
| /* Transmitted to client. Then close the handle & |
| * get the new handle for next transmission & reception. |
| */ |
| close_sock_handle(g_rwl_hndle); |
| #endif /* RWL_SOCKET */ |
| continue; |
| #endif /* WIN32 */ |
| } /* REMOTE_SHELL_CMD */ |
| |
| #ifdef RWLASD |
| if (g_rem_ptr->msg.flags & REMOTE_ASD_CMD) { |
| if ((err = remote_asd_exec(buf_ptr, (int *)&g_rem_ptr->msg.len)) < 0) { |
| DPRINT_ERR(ERR, "Error in executing asd command\n"); |
| } |
| } /* REMOTE_ASD_CMD */ |
| #endif |
| |
| /* |
| * added to take care of OID base problem for cross OS RWL cleint server |
| * In case of LX Server and WIN32 client OID base need to be removed |
| * In case of WIN32 server and LX client OID base need to be added |
| */ |
| if (!(g_rem_ptr->msg.flags & REMOTE_ASD_CMD)) { |
| #if defined(LINUX) |
| if (g_rem_ptr->msg.cmd > MAX_IOVAR) |
| g_rem_ptr->msg.cmd -= WL_OID_BASE; |
| #endif |
| #if defined(WIN32) |
| if (g_rem_ptr->msg.cmd < MAX_IOVAR) |
| g_rem_ptr->msg.cmd += WL_OID_BASE; |
| #endif |
| } |
| #ifdef VISTA_SERVER |
| if (g_rem_ptr->msg.flags & REMOTE_VISTA_CMD) { |
| vista_buf[0] = strtok(buf_ptr, " \t\n"); |
| for (index = 1; (vista_buf[index] = strtok(NULL, " \t\n")) != NULL; |
| index++); |
| if ((err = remote_vista_exec(wl, vista_buf)) < 0) { |
| DPRINT_ERR(ERR, "Error in executing vista command\n"); |
| } |
| memcpy(buf_ptr, vista_buf[0], strlen(vista_buf[0])); |
| g_rem_ptr->msg.len = strlen(vista_buf[0]); |
| } /* REMOTE_VISTA_CMD */ |
| #endif /* VISTA_SERVER */ |
| |
| #ifndef OLYMPIC_RWL |
| #if defined(LINUX) |
| #ifndef RWL_DONGLE |
| if (g_rem_ptr->msg.flags & REMOTE_GET_IOCTL || |
| g_rem_ptr->msg.flags & REMOTE_SET_IOCTL) { |
| if (strlen(g_rem_ptr->intf_name) != 0) { |
| struct ifreq ifr; |
| /* validate the interface */ |
| memset(&ifr, 0, sizeof(ifr)); |
| if (g_rem_ptr->intf_name) |
| strncpy(ifr.ifr_name, g_rem_ptr->intf_name, IFNAMSIZ); |
| |
| if (wl_check((void *)&ifr)) { |
| DPRINT_ERR(ERR, "%s: wl driver adapter not found\n", |
| g_rem_ptr->intf_name); |
| /* Signal end of command output */ |
| g_rem_ptr->msg.len = 0; |
| remote_tx_response(wl, NULL, BCME_NODEVICE); |
| if (buf_ptr) |
| free(buf_ptr); |
| #ifdef RWL_SOCKET |
| close_sock_handle(g_rwl_hndle); |
| #endif |
| continue; |
| } |
| |
| if (set_interface(wl, g_rem_ptr->intf_name) == BCME_OK) |
| DPRINT_DBG(OUTPUT, "\n %s Interface will be used \n", |
| (char *)wl); |
| } |
| } |
| #endif /* ifndef RWL_DONGLE */ |
| #endif /* defined(LINUX) */ |
| #endif /* ifndef OLYMPIC_RWL */ |
| if (g_rem_ptr->msg.flags & REMOTE_SET_IOCTL || |
| g_rem_ptr->msg.flags & RDHD_SET_IOCTL) { |
| #ifdef WIN32 |
| #if defined(RWL_DONGLE) || defined(RWL_WIFI) |
| /* For commands with msg length as zero initialize the buffer to null */ |
| if (g_rem_ptr->msg.len == 0) |
| buf_ptr = NULL; |
| #endif |
| #else |
| if (g_rem_ptr->msg.len == 0) |
| buf_ptr = NULL; |
| #endif /* WIN32 */ |
| |
| #if defined(LINUX) || defined(TARGETOS_symbian) || defined(TARGETOS_nucleus) |
| #ifdef OLYMPIC_RWL |
| set_interface(wl, old_intf_name); |
| #endif |
| if (g_rem_ptr->msg.flags & REMOTE_SET_IOCTL) { |
| if (g_rem_ptr->msg.cmd == WLC_SET_VAR && buf_ptr && |
| !strncmp((const char *)buf_ptr, |
| "init", g_rem_ptr->msg.len)) { |
| DPRINT_INFO(OUTPUT, "REC : init command\n"); |
| err = 0; |
| } else if (g_rem_ptr->msg.cmd == WLC_SET_VAR && buf_ptr && |
| !strncmp((const char *)buf_ptr, |
| "download", g_rem_ptr->msg.len)) { |
| DPRINT_INFO(OUTPUT, "REC : download command\n"); |
| download_flag = download_flag? 0: 1; |
| if (download_flag) { |
| DPRINT_INFO(OUTPUT, "download started\n"); |
| if (!(fp = fopen(fn, "wb"))) { |
| DPRINT_ERR(ERR, "Failed to open file\n"); |
| err = -2; |
| } |
| } else { |
| DPRINT_INFO(OUTPUT, "download completed\n"); |
| if (fp != NULL) { |
| (void)fclose(fp); |
| fp = NULL; |
| } |
| } |
| err = 0; |
| } else if (g_rem_ptr->msg.cmd == WLC_SET_VAR && buf_ptr && |
| !strncmp((const char *)buf_ptr, |
| "nvdownload", g_rem_ptr->msg.len)) { |
| DPRINT_INFO(OUTPUT, "REC : nvram download command\n"); |
| download_flag = download_flag? 0: 1; |
| if (download_flag) { |
| DPRINT_INFO(OUTPUT, "nvram download started\n"); |
| if (!(fp = fopen(fw, "wb"))) { |
| DPRINT_ERR(ERR, "Failed to open file\n"); |
| err = -2; |
| } |
| } else { |
| DPRINT_INFO(OUTPUT, "nvram download completed\n"); |
| if (fp != NULL) { |
| (void)fclose(fp); |
| fp = NULL; |
| } |
| } |
| err = 0; |
| } else if (g_rem_ptr->msg.cmd == WLC_SET_VAR && buf_ptr && |
| !strncmp((const char *)buf_ptr, |
| "membytes", g_rem_ptr->msg.len)) { |
| DPRINT_INFO(OUTPUT, "REC : membytes command\n"); |
| skip = strlen("membytes ") + 8; |
| if (fp != NULL) |
| fwrite(buf_ptr + skip, 1, |
| g_rem_ptr->msg.len - skip, fp); |
| else |
| DPRINT_ERR(ERR, "Download file has been closed.\n"); |
| err = 0; |
| } else { |
| err = wl_ioctl(wl, g_rem_ptr->msg.cmd, |
| (void *)buf_ptr, g_rem_ptr->msg.len, TRUE); |
| DPRINT_INFO(OUTPUT, "SEND : cmd %d\t msg len %d\n", |
| g_rem_ptr->msg.cmd, g_rem_ptr->msg.len); |
| DPRINT_INFO(OUTPUT, "error code: %d\n", err); |
| } |
| } |
| #if defined(LINUX) |
| if (err == BCME_IOCTL_ERROR) { |
| if (rwl_var_getbuf(wl, "bcmerrorstr", NULL, 0, (void**)&errstr)) { |
| DPRINT_ERR(ERR, "Error in executing wl_ioctl\r\n"); |
| } else { |
| DPRINT_ERR(ERR, "%s\n", errstr); |
| } |
| DPRINT_ERR(ERR, "Setting Default Interface1 \n"); |
| set_interface(wl, old_intf_name); |
| } |
| |
| if (g_rem_ptr->msg.flags & RDHD_SET_IOCTL) { |
| err = dhd_ioctl(wl, g_rem_ptr->msg.cmd, |
| (void *)buf_ptr, g_rem_ptr->msg.len, TRUE); |
| } |
| #endif /* LINUX */ |
| |
| #elif WIN32 |
| dwlen = g_rem_ptr->msg.len; |
| if (g_rem_ptr->msg.flags & RDHD_SET_IOCTL) { |
| g_rem_ptr->msg.cmd = g_rem_ptr->msg.cmd |
| - WL_OID_BASE + OID_DHD_IOCTLS; |
| } |
| |
| err = (int)ir_setinformation(wl, g_rem_ptr->msg.cmd, |
| buf_ptr, &dwlen); |
| #endif |
| g_rem_ptr->msg.flags = REMOTE_SET_IOCTL; |
| |
| } /* RDHD/REMOTE_SET_IOCTL */ |
| |
| if (g_rem_ptr->msg.flags & REMOTE_GET_IOCTL || |
| g_rem_ptr->msg.flags & RDHD_GET_IOCTL) { |
| #if defined(LINUX) || defined(TARGETOS_symbian) || defined(TARGETOS_nucleus) |
| if (g_rem_ptr->msg.cmd == WLC_GET_VAR && buf_ptr && |
| strncmp((const char *)buf_ptr, "exit", g_rem_ptr->msg.len) == 0) { |
| /* exit command from remote client terminates server */ |
| free(buf_ptr); |
| break; |
| } |
| if (g_rem_ptr->msg.flags & REMOTE_GET_IOCTL) |
| err = wl_ioctl(wl, g_rem_ptr->msg.cmd, (void *)buf_ptr, |
| g_rem_ptr->msg.len, FALSE); |
| #ifdef PCIE_MFGTEST |
| if (err == CMD_ERR && |
| g_rem_ptr->msg.cmd == WLC_GET_MAGIC && |
| g_rem_ptr->msg.len == 4) { |
| err = 0; |
| DPRINT_ERR(ERR, "----command error \n"); |
| buf_ptr[0] = WLC_IOCTL_MAGIC & 0xff; // 0x77 |
| buf_ptr[1] = (WLC_IOCTL_MAGIC >> 8) & 0xff; // 0x6c |
| buf_ptr[2] = (WLC_IOCTL_MAGIC >> 16) & 0xff; // 0xe4; |
| buf_ptr[3] = (WLC_IOCTL_MAGIC >> 24) & 0xff; // 0x14; |
| } |
| #endif /* PCIE_MFGTEST */ |
| #if defined(LINUX) |
| if (err == BCME_IOCTL_ERROR) { |
| #ifdef PCIE_MFGTEST |
| if (g_rem_ptr->msg.cmd == WLC_GET_VERSION && |
| g_rem_ptr->msg.len == 4) { |
| err = 0; |
| DPRINT_ERR(ERR, "---getversion \n"); |
| buf_ptr[0] = WLC_IOCTL_VERSION & 0xff; |
| buf_ptr[1] = (WLC_IOCTL_VERSION >> 8) & 0xff; |
| buf_ptr[2] = (WLC_IOCTL_VERSION >> 16) & 0xff; |
| buf_ptr[3] = (WLC_IOCTL_VERSION >> 24) & 0xff; |
| } |
| else { |
| DPRINT_ERR(ERR, "REMOTE_GET_IOCTL::Error in executing" |
| " wl_ioctl\n"); |
| DPRINT_ERR(ERR, "Setting Default Interface \n"); |
| set_interface(wl, old_intf_name); |
| } |
| #else |
| if (rwl_var_getbuf(wl, "bcmerrorstr", NULL, 0, (void**)&errstr)) { |
| DPRINT_ERR(ERR, |
| "REMOTE_GET_IOCTL::Error in executing wl_ioctl\n"); |
| } else { |
| DPRINT_ERR(ERR, "%s\n", errstr); |
| } |
| DPRINT_ERR(ERR, "Setting Default Interface \n"); |
| set_interface(wl, old_intf_name); |
| #endif /* PCIE_MFGTEST */ |
| } |
| |
| if (g_rem_ptr->msg.flags & RDHD_GET_IOCTL) |
| err = dhd_ioctl(wl, g_rem_ptr->msg.cmd, (void *)buf_ptr, |
| g_rem_ptr->msg.len, FALSE); |
| #endif /* LINUX */ |
| #elif WIN32 |
| if (g_rem_ptr->msg.cmd == (WL_OID_BASE + WLC_GET_VAR) && |
| strncmp(buf_ptr, "exit", g_rem_ptr->msg.len) == 0) { |
| /* exit command from remote client terminates server */ |
| if (buf_ptr) { |
| free(buf_ptr); |
| } |
| break; |
| } |
| |
| dwlen = g_rem_ptr->msg.len; |
| if (g_rem_ptr->msg.flags & RDHD_GET_IOCTL) { |
| g_rem_ptr->msg.cmd = g_rem_ptr->msg.cmd - |
| WL_OID_BASE + OID_DHD_IOCTLS; |
| } |
| |
| err = (int)ir_queryinformation(wl, |
| g_rem_ptr->msg.cmd, buf_ptr, &dwlen); |
| |
| #endif /* defined(LINUX) || defined(TARGETOS_symbian) || defined(TARGETOS_nucleus) */ |
| g_rem_ptr->msg.flags = REMOTE_GET_IOCTL; |
| } /* REMOTE_GET_IOCTL */ |
| DPRINT_INFO(OUTPUT, "RESP : cmd %d\t msg len %d\n", |
| g_rem_ptr->msg.cmd, g_rem_ptr->msg.len); |
| #if defined(LINUX) |
| /* setting back default interface */ |
| set_interface(wl, old_intf_name); |
| #endif /* defined(LINUX) */ |
| /* Transmit the response results */ |
| if (remote_tx_response(wl, buf_ptr, err) < 0) { |
| DPRINT_ERR(ERR, "\nReturn results failed\n"); |
| } |
| |
| #ifdef RWL_SOCKET |
| if (g_rem_ptr->msg.flags != REMOTE_SHELL_CMD) |
| /* Transmitted to client. Then close the handle & get the new handle |
| * for next transmission & reception. In case of shell commands this |
| * should be closed in respective shellproc files. |
| */ |
| close_sock_handle(g_rwl_hndle); |
| #endif /* RWL_SOCKET */ |
| |
| if (buf_ptr) { |
| free(buf_ptr); |
| } |
| } /* end of while */ |
| #if defined(RWL_SOCKET) |
| /* Close the main handle for socket */ |
| close_sock_handle(transport_descriptor); |
| #elif defined(RWL_SERIAL) |
| /* Close the main handle for serial pipe */ |
| rwl_close_pipe(remote_type, (void*)&transport_descriptor); |
| #endif |
| |
| #ifdef RWLASD |
| wfa_dut_deinit(); |
| #endif |
| |
| return err; |
| } |