/** * Node Transport Processing * * This function is part of the callback system for the Ethernet transport. * Based on the Command Group field in the header, it will call the appropriate * processing function. * * @param Message to Node - WARPNet Host Message to the node * Message from Node - WARPNet Host Message from the node * Packet Source - Ethernet Packet Source * Ethernet Device Number - Indicates which Ethernet device packet came from * * @return None. * * @note None. * ******************************************************************************/ void node_rxFromTransport(wn_host_message* toNode, wn_host_message* fromNode, void* pktSrc, unsigned int eth_dev_num){ unsigned char cmd_grp; unsigned int respSent; #ifdef _DEBUG_ xil_printf("In node_rxFromTransport() \n"); #endif //Helper struct pointers to interpret the received packet contents wn_cmdHdr* cmdHdr; void * cmdArgs; //Helper struct pointers to form a response packet wn_respHdr* respHdr; void * respArgs; cmdHdr = (wn_cmdHdr*)(toNode->payload); cmdArgs = (toNode->payload) + sizeof(wn_cmdHdr); //Endian swap the command header (this is the first place we know what/where it is) cmdHdr->cmd = Xil_Ntohl(cmdHdr->cmd); cmdHdr->length = Xil_Ntohs(cmdHdr->length); cmdHdr->numArgs = Xil_Ntohs(cmdHdr->numArgs); //Outgoing response header must be endian swapped as it's filled in respHdr = (wn_respHdr*)(fromNode->payload); respArgs = (fromNode->payload) + sizeof(wn_cmdHdr); cmd_grp = WN_CMD_TO_GRP(cmdHdr->cmd); switch(cmd_grp){ case WARPNET_GRP: case NODE_GRP: respSent = node_processCmd(cmdHdr,cmdArgs,respHdr,respArgs, pktSrc, eth_dev_num); break; case TRANS_GRP: respSent = transport_processCmd(cmdHdr,cmdArgs,respHdr,respArgs, pktSrc, eth_dev_num); break; default: xil_printf("Unknown command group\n"); break; } if(respSent == NO_RESP_SENT) fromNode->length += (respHdr->length + sizeof(wn_cmdHdr)); //Endian swap the response header before returning // Do it here so the transport sender doesn't have to understand any payload contents respHdr->cmd = Xil_Ntohl(respHdr->cmd); respHdr->length = Xil_Ntohs(respHdr->length); respHdr->numArgs = Xil_Ntohs(respHdr->numArgs); return; }
/** * Node Send Early Response * * Allows a node to send a response back to the host before the command has * finished being processed. This is to minimize the latency between commands * since the node is able to finish processing the command during the time * it takes to communicate to the host and receive another command. * * @param Response Header - WARPNet Response Header * Packet Source - Ethernet Packet Source * Ethernet Device Number - Indicates which Ethernet device packet came from * * @return None. * * @note None. * ******************************************************************************/ void node_sendEarlyResp(wn_respHdr* respHdr, void* pktSrc, unsigned int eth_dev_num){ /* This function is used to send multiple command responses back to the host * under the broader umbrella of a single command exchange. The best example * of this functionality is a 'readIQ' command where a single packet from * the host results in many response packets returning from the board. * * A key assumption in the use of this function is that the underlying command * from the host does not raise the transport-level ACK flag in the transport * header. Furthermore, this function exploits the fact that wn_node can determine * the beginning of the overall send buffer from the location of the response to * be sent. */ wn_host_message nodeResp; #ifdef _DEBUG_ xil_printf("In node_sendEarlyResp() \n"); #endif nodeResp.payload = (void*) respHdr; nodeResp.buffer = (void*) respHdr - ( PAYLOAD_OFFSET + sizeof(wn_transport_header) ); nodeResp.length = PAYLOAD_PAD_NBYTES + respHdr->length + sizeof(wn_cmdHdr); //Extra 2 bytes is for alignment //Endian swap the response header before before transport sends it // Do it here so the transport sender doesn't have to understand any payload contents respHdr->cmd = Xil_Ntohl(respHdr->cmd); respHdr->length = Xil_Ntohs(respHdr->length); respHdr->numArgs = Xil_Ntohs(respHdr->numArgs); #ifdef _DEBUG_ xil_printf("sendEarlyResp\n"); xil_printf("payloadAddr = 0x%x, bufferAddr = 0x%x, len = %d\n",nodeResp.payload,nodeResp.buffer,nodeResp.length); #endif transport_send(&nodeResp, pktSrc, eth_dev_num); }
void wlan_poll_eth() { XAxiDma_BdRing *rxRing_ptr; XAxiDma_Bd *cur_bd_ptr; XAxiDma_Bd *first_bd_ptr; u8* mpdu_start_ptr; u8* eth_start_ptr; u8* eth_mid_ptr; packet_bd* tx_queue; u32 eth_rx_len, eth_rx_buf; u32 mpdu_tx_len; packet_bd_list tx_queue_list; u32 i; u8 continue_loop; int bd_count; int status; int packet_is_queued; ethernet_header* eth_hdr; ipv4_header* ip_hdr; arp_packet* arp; udp_header* udp; dhcp_packet* dhcp; llc_header* llc_hdr; u8 eth_dest[6]; u8 eth_src[6]; static u32 max_bd_count = 0; rxRing_ptr = XAxiDma_GetRxRing(Ð_A_DMA_Instance); //Check if any Rx BDs have been executed //TODO: process XAXIDMA_ALL_BDS instead of 1 at a time //bd_count = XAxiDma_BdRingFromHw(rxRing_ptr, 1, &cur_bd_ptr); bd_count = XAxiDma_BdRingFromHw(rxRing_ptr, XAXIDMA_ALL_BDS, &first_bd_ptr); cur_bd_ptr = first_bd_ptr; if(bd_count > max_bd_count){ max_bd_count = bd_count; //xil_printf("max_bd_count = %d\n",max_bd_count); } if(bd_count == 0) { //No Rx BDs have been processed - no new Eth receptions waiting return; } for(i=0;i<bd_count;i++){ //A packet has been received and transferred by DMA tx_queue = (packet_bd*)XAxiDma_BdGetId(cur_bd_ptr); //xil_printf("DMA has filled in packet_bd at 0x%08x\n", tx_queue); eth_rx_len = XAxiDma_BdGetActualLength(cur_bd_ptr, rxRing_ptr->MaxTransferLen); eth_rx_buf = XAxiDma_BdGetBufAddr(cur_bd_ptr); //After encapsulation, byte[0] of the MPDU will be at byte[0] of the queue entry frame buffer mpdu_start_ptr = (void*)((tx_packet_buffer*)(tx_queue->buf_ptr))->frame; eth_start_ptr = (u8*)eth_rx_buf; //Calculate actual wireless Tx len (eth payload - eth header + wireless header) mpdu_tx_len = eth_rx_len - sizeof(ethernet_header) + sizeof(llc_header) + sizeof(mac_header_80211); //Helper pointers to interpret/fill fields in the new MPDU eth_hdr = (ethernet_header*)eth_start_ptr; llc_hdr = (llc_header*)(mpdu_start_ptr + sizeof(mac_header_80211)); //Copy the src/dest addresses from the received Eth packet to temp space memcpy(eth_src, eth_hdr->address_source, 6); memcpy(eth_dest, eth_hdr->address_destination, 6); //Prepare the MPDU LLC header llc_hdr->dsap = LLC_SNAP; llc_hdr->ssap = LLC_SNAP; llc_hdr->control_field = LLC_CNTRL_UNNUMBERED; bzero((void *)(llc_hdr->org_code), 3); //Org Code 0x000000: Encapsulated Ethernet packet_is_queued = 0; packet_bd_list tx_queue_list; packet_bd_list_init(&tx_queue_list); packet_bd_insertEnd(&tx_queue_list, tx_queue); switch(eth_encap_mode){ case ENCAP_MODE_AP: switch(eth_hdr->type) { case ETH_TYPE_ARP: llc_hdr->type = LLC_TYPE_ARP; packet_is_queued = eth_rx_callback(&tx_queue_list, eth_dest, eth_src, mpdu_tx_len); break; case ETH_TYPE_IP: llc_hdr->type = LLC_TYPE_IP; packet_is_queued = eth_rx_callback(&tx_queue_list, eth_dest, eth_src, mpdu_tx_len); break; /* WMP_START */ case WMP4WARP_ETHER_TYPE: wmp_high_util_handle_wmp_cmd_from_ethernet(eth_hdr); break; /* WMP_END */ default: //Unknown/unsupported EtherType; don't process the Eth frame break; } break; case ENCAP_MODE_STA: //Save this ethernet src address for d memcpy(eth_sta_mac_addr, eth_src, 6); memcpy(eth_src, hw_info.hw_addr_wlan, 6); switch(eth_hdr->type) { case ETH_TYPE_ARP: arp = (arp_packet*)((void*)eth_hdr + sizeof(ethernet_header)); //Here we hijack ARP messages and overwrite their source MAC address field with //the station's wireless MAC address. memcpy(arp->eth_src, hw_info.hw_addr_wlan, 6); llc_hdr->type = LLC_TYPE_ARP; packet_is_queued = eth_rx_callback(&tx_queue_list, eth_dest, eth_src, mpdu_tx_len); break; case ETH_TYPE_IP: llc_hdr->type = LLC_TYPE_IP; ip_hdr = (ipv4_header*)((void*)eth_hdr + sizeof(ethernet_header)); if(ip_hdr->prot == IPV4_PROT_UDP){ udp = (udp_header*)((void*)ip_hdr + 4*((u8)(ip_hdr->ver_ihl) & 0xF)); udp->checksum = 0; //Disable the checksum since we are about to mess with the bytes in the packet if(Xil_Ntohs(udp->src_port) == UDP_SRC_PORT_BOOTPC || Xil_Ntohs(udp->src_port) == UDP_SRC_PORT_BOOTPS){ //This is a DHCP Discover packet, which contains the source hardware address //deep inside the packet (in addition to its usual location in the Eth header). //For STA encapsulation, we need to overwrite this address with the MAC addr //of the wireless station. dhcp = (dhcp_packet*)((void*)udp + sizeof(udp_header)); if(Xil_Ntohl(dhcp->magic_cookie) == DHCP_MAGIC_COOKIE){ eth_mid_ptr = (u8*)((void*)dhcp + sizeof(dhcp_packet)); dhcp->flags = Xil_Htons(DHCP_BOOTP_FLAGS_BROADCAST); //Tagged DHCP Options continue_loop = 1; while(continue_loop){ switch(eth_mid_ptr[0]){ case DHCP_OPTION_TAG_TYPE: switch(eth_mid_ptr[2]){ case DHCP_OPTION_TYPE_DISCOVER: case DHCP_OPTION_TYPE_REQUEST: //memcpy(dhcp->chaddr,hw_info.hw_addr_wlan,6); break; } break; case DHCP_OPTION_TAG_IDENTIFIER: //memcpy(&(eth_mid_ptr[3]),hw_info.hw_addr_wlan,6); break; case DHCP_OPTION_END: continue_loop = 0; break; } eth_mid_ptr += (2+eth_mid_ptr[1]); } } } } packet_is_queued = eth_rx_callback(&tx_queue_list, eth_dest, eth_src, mpdu_tx_len); break; /* WMP_START */ case WMP4WARP_ETHER_TYPE:{ wmp_high_util_handle_wmp_cmd_from_ethernet(eth_hdr); break;} /* WMP_END */ default: //Unknown/unsupported EtherType; don't process the Eth frame break; } break; } if(packet_is_queued == 0){ //xil_printf(" ...checking in\n"); queue_checkin(&tx_queue_list); } //TODO: Option A: We free this single BD and run the routine to checkout as many queues as we can and hook them up to BDs //Results: pretty good TCP performance //Free this bd status = XAxiDma_BdRingFree(rxRing_ptr, 1, cur_bd_ptr); if(status != XST_SUCCESS) {xil_printf("Error in XAxiDma_BdRingFree of Rx BD! Err = %d\n", status); return;} wlan_eth_dma_update(); //Update cur_bd_ptr to the next BD in the chain for the next iteration cur_bd_ptr = XAxiDma_BdRingNext(rxRing_ptr, cur_bd_ptr); } //TODO: Option B: We free all BDs at once and run the routine to checkout as many queues as we can and hook them up to BDs //Results: pretty lackluster TCP performance. needs further investigation //Free this bd //status = XAxiDma_BdRingFree(rxRing_ptr, bd_count, first_bd_ptr); //if(status != XST_SUCCESS) {xil_printf("Error in XAxiDma_BdRingFree of Rx BD! Err = %d\n", status); return;} //wlan_eth_dma_update(); return; }
//De-encapsulate packet and send over Ethernet int wlan_mpdu_eth_send(void* mpdu, u16 length){ int status; u8* eth_mid_ptr; mac_header_80211* rx80211_hdr; llc_header* llc_hdr; ethernet_header* eth_hdr; u8 continue_loop; ipv4_header* ip_hdr; arp_packet* arp; udp_header* udp; dhcp_packet* dhcp; u8 addr_cache[6]; switch(eth_encap_mode){ case ENCAP_MODE_AP: rx80211_hdr = (mac_header_80211*)((void *)mpdu); llc_hdr = (llc_header*)((void *)mpdu + sizeof(mac_header_80211)); eth_hdr = (ethernet_header*)((void *)mpdu + sizeof(mac_header_80211) + sizeof(llc_header) - sizeof(ethernet_header)); length = length - sizeof(mac_header_80211) - sizeof(llc_header) + sizeof(ethernet_header); memmove(eth_hdr->address_destination, rx80211_hdr->address_3, 6); memmove(eth_hdr->address_source, rx80211_hdr->address_2, 6); switch(llc_hdr->type){ case LLC_TYPE_ARP: //xil_printf("Sending ARP\n"); eth_hdr->type = ETH_TYPE_ARP; break; case LLC_TYPE_IP: //xil_printf("Sending IP\n"); eth_hdr->type = ETH_TYPE_IP; break; default: //Invalid or unsupported Eth type; punt return -1; break; } break; case ENCAP_MODE_STA: rx80211_hdr = (mac_header_80211*)((void *)mpdu); llc_hdr = (llc_header*)((void *)mpdu + sizeof(mac_header_80211)); eth_hdr = (ethernet_header*)((void *)mpdu + sizeof(mac_header_80211) + sizeof(llc_header) - sizeof(ethernet_header)); length = length - sizeof(mac_header_80211) - sizeof(llc_header) + sizeof(ethernet_header); if(wlan_addr_eq(rx80211_hdr->address_3, hw_info.hw_addr_wlan)){ //This case handles the behavior of an AP reflecting a station-sent broadcast packet back out over the air. //Without this filtering, a station would see its own packet. This leads to very bad DHCP and ARP behavior. return -1; } ///DEBUG memcpy(addr_cache,rx80211_hdr->address_3,6); if(wlan_addr_eq(rx80211_hdr->address_1,hw_info.hw_addr_wlan)){ memcpy(eth_hdr->address_destination, eth_sta_mac_addr, 6); } else { memmove(eth_hdr->address_destination, rx80211_hdr->address_1, 6); } //memmove(eth_hdr->address_source, rx80211_hdr->address_3, 6); memcpy(eth_hdr->address_source, addr_cache,6); switch(llc_hdr->type){ case LLC_TYPE_ARP: arp = (arp_packet*)((void*)eth_hdr + sizeof(ethernet_header)); // Here we hijack ARP messages and overwrite their source MAC address field with // the Ethernet-connected client's MAC address if(wlan_addr_eq(arp->eth_dst,hw_info.hw_addr_wlan)){ memcpy(arp->eth_dst, eth_sta_mac_addr, 6); } eth_hdr->type = ETH_TYPE_ARP; break; case ETH_TYPE_IP: eth_hdr->type = ETH_TYPE_IP; ip_hdr = (ipv4_header*)((void*)eth_hdr + sizeof(ethernet_header)); if(ip_hdr->prot == IPV4_PROT_UDP){ udp = (udp_header*)((void*)ip_hdr + 4*((u8)(ip_hdr->ver_ihl) & 0xF)); udp->checksum = 0; //Disable the checksum since we are about to mess with the bytes in the packet if(Xil_Ntohs(udp->src_port) == UDP_SRC_PORT_BOOTPC || Xil_Ntohs(udp->src_port) == UDP_SRC_PORT_BOOTPS){ //This is a DHCP Discover packet, which contains the source hardware address //deep inside the packet (in addition to its usual location in the Eth header). //For STA encapsulation, we need to overwrite this address with the MAC addr //of the wireless station. dhcp = (dhcp_packet*)((void*)udp + sizeof(udp_header)); if(Xil_Ntohl(dhcp->magic_cookie) == DHCP_MAGIC_COOKIE){ eth_mid_ptr = (u8*)((void*)dhcp + sizeof(dhcp_packet)); //Tagged DHCP Options continue_loop = 1; while(continue_loop){ switch(eth_mid_ptr[0]){ case DHCP_OPTION_TAG_TYPE: switch(eth_mid_ptr[2]){ case DHCP_OPTION_TYPE_DISCOVER: case DHCP_OPTION_TYPE_REQUEST: //memcpy(dhcp->chaddr,hw_info.hw_addr_wlan,6); break; case DHCP_OPTION_TYPE_ACK: break; case DHCP_OPTION_TYPE_OFFER: break; } break; case DHCP_OPTION_TAG_IDENTIFIER: // memcpy(&(eth_mid_ptr[3]),eth_sta_mac_addr,6); break; case DHCP_OPTION_END: continue_loop = 0; break; } eth_mid_ptr += (2+eth_mid_ptr[1]); } // } } } } break; default: //Invalid or unsupported Eth type; punt return -1; break; } break; } status = wlan_eth_dma_send((u8*)eth_hdr, length); if(status != 0) {xil_printf("Erroor in wlan_mac_send_eth! Err = %d\n", status); return -1;} return 0; }
/** * Node Commands * * This function is part of the callback system for the Ethernet transport * and will be executed when a valid node commands is recevied. * * @param Command Header - WARPNet Command Header * Command Arguments - WARPNet Command Arguments * Response Header - WARPNet Response Header * Response Arguments - WARPNet Response Arguments * Packet Source - Ethernet Packet Source * Ethernet Device Number - Indicates which Ethernet device packet came from * * @return None. * * @note See on-line documentation for more information about the ethernet * packet structure for WARPNet: www.warpproject.org * ******************************************************************************/ int node_processCmd(const wn_cmdHdr* cmdHdr,const void* cmdArgs, wn_respHdr* respHdr,void* respArgs, void* pktSrc, unsigned int eth_dev_num){ //IMPORTANT ENDIAN NOTES: // -cmdHdr is safe to access directly (pre-swapped if needed) // -cmdArgs is *not* pre-swapped, since the framework doesn't know what it is // -respHdr will be swapped by the framework; user code should fill it normally // -respArgs will *not* be swapped by the framework, since only user code knows what it is // Any data added to respArgs by the code below must be endian-safe (swapped on AXI hardware) int status = 0; const u32 * cmdArgs32 = cmdArgs; u32 * respArgs32 = respArgs; unsigned int respIndex = 0; unsigned int respSent = NO_RESP_SENT; unsigned int max_words = 320; // Max number of u32 words that can be sent in the packet (~1400 bytes) // If we need more, then we will need to rework this to send multiple response packets unsigned int temp, i; // Variables for functions u32 id; u32 flags; u32 start_address; u32 curr_address; u32 next_address; u32 size; u32 evt_log_size; u32 transfer_size; u32 bytes_per_pkt; u32 num_bytes; u32 num_pkts; u32 interval; unsigned int cmdID; cmdID = WN_CMD_TO_CMDID(cmdHdr->cmd); respHdr->cmd = cmdHdr->cmd; respHdr->length = 0; respHdr->numArgs = 0; #ifdef _DEBUG_ xil_printf("In node_processCmd(): ID = %d \n", cmdID); #endif switch(cmdID){ //--------------------------------------------------------------------- case WARPNET_TYPE: // Return the WARPNet Type respArgs32[respIndex++] = Xil_Htonl( node_info.type ); respHdr->length += (respIndex * sizeof(respArgs32)); respHdr->numArgs = respIndex; break; //--------------------------------------------------------------------- case NODE_INFO: // Return the info about the WLAN_EXP_NODE // Send node parameters temp = node_get_parameters( &respArgs32[respIndex], max_words, TRANSMIT_OVER_NETWORK); respIndex += temp; max_words -= temp; if ( max_words <= 0 ) { xil_printf("No more space left in NODE_INFO packet \n"); }; // Send transport parameters temp = transport_get_parameters( eth_dev_num, &respArgs32[respIndex], max_words, TRANSMIT_OVER_NETWORK); respIndex += temp; max_words -= temp; if ( max_words <= 0 ) { xil_printf("No more space left in NODE_INFO packet \n"); }; #ifdef _DEBUG_ xil_printf("NODE INFO: \n"); for ( i = 0; i < respIndex; i++ ) { xil_printf(" [%2d] = 0x%8x \n", i, respArgs32[i]); } xil_printf("END NODE INFO \n"); #endif // -------------------------------- // Future parameters go here // -------------------------------- // Finalize response respHdr->length += (respIndex * sizeof(respArgs32)); respHdr->numArgs = respIndex; break; //--------------------------------------------------------------------- case NODE_IDENTIFY: // Return Null Response // The WLAN_EXP_NODE currently does not have access to LEDs xil_printf(" Node: %d IP Address: %d.%d.%d.%d \n", node_info.node, node_info.ip_addr[0], node_info.ip_addr[1],node_info.ip_addr[2],node_info.ip_addr[3]); // -------------------------------- // TODO: Add in visual identifiers for the node // -------------------------------- break; //--------------------------------------------------------------------- case NODE_CONFIG_SETUP: // NODE_CONFIG_SETUP Packet Format: // - Note: All u32 parameters in cmdArgs32 are byte swapped so use Xil_Ntohl() // // - cmdArgs32[0] - Serial Number // - cmdArgs32[1] - Node ID // - cmdArgs32[2] - IP Address // - cmdArgs32[3] - Unicast Port // - cmdArgs32[4] - Broadcast Port // if ( node_info.node == 0xFFFF ) { // Only update the parameters if the serial numbers match if ( node_info.serial_number == Xil_Ntohl(cmdArgs32[0]) ) { xil_printf(" Reconfiguring ETH %c \n", wn_conv_eth_dev_num(eth_dev_num) ); node_info.node = Xil_Ntohl(cmdArgs32[1]) & 0xFFFF; xil_printf(" New Node ID : %d \n", node_info.node); // Grab New IP Address node_info.ip_addr[0] = (Xil_Ntohl(cmdArgs32[2]) >> 24) & 0xFF; node_info.ip_addr[1] = (Xil_Ntohl(cmdArgs32[2]) >> 16) & 0xFF; node_info.ip_addr[2] = (Xil_Ntohl(cmdArgs32[2]) >> 8) & 0xFF; node_info.ip_addr[3] = (Xil_Ntohl(cmdArgs32[2]) ) & 0xFF; // Grab new ports node_info.unicast_port = Xil_Ntohl(cmdArgs32[3]); node_info.broadcast_port = Xil_Ntohl(cmdArgs32[4]); xil_printf(" New IP Address : %d.%d.%d.%d \n", node_info.ip_addr[0], node_info.ip_addr[1],node_info.ip_addr[2],node_info.ip_addr[3]); xil_printf(" New Unicast Port : %d \n", node_info.unicast_port); xil_printf(" New Broadcast Port: %d \n", node_info.broadcast_port); transport_set_hw_info( eth_dev_num, node_info.ip_addr, node_info.hw_addr); status = transport_config_sockets(eth_dev_num, node_info.unicast_port, node_info.broadcast_port); if(status != 0) { xil_printf("Error binding transport...\n"); } } else { xil_printf("NODE_IP_SETUP Packet with Serial Number %d ignored. My serial number is %d \n", Xil_Ntohl(cmdArgs32[0]), node_info.serial_number); } }
/** * Process Transport Commands * * This function is part of the Ethernet processing system and will process the * various transport related commands. * * @param socket_index - Index of the socket on which to send message * @param from - Pointer to socket address structure (struct sockaddr *) where command is from * @param command - Pointer to Command * @param response - Pointer to Response * @param max_resp_len - Maximum number of u32 words allowed in response * * @return int - Status of the command: * NO_RESP_SENT - No response has been sent * RESP_SENT - A response has been sent * * @note See on-line documentation for more information about the Ethernet * packet structure: www.warpproject.org * *****************************************************************************/ int process_transport_cmd(int socket_index, void * from, cmd_resp * command, cmd_resp * response, u32 max_resp_len) { // // IMPORTANT ENDIAN NOTES: // - command // - header - Already endian swapped by the framework (safe to access directly) // - args - Must be endian swapped as necessary by code (framework does not know the contents of the command) // - response // - header - Will be endian swapped by the framework (safe to write directly) // - args - Must be endian swapped as necessary by code (framework does not know the contents of the response) // // Standard variables u32 resp_sent = NO_RESP_SENT; cmd_resp_hdr * cmd_hdr = command->header; u32 * cmd_args_32 = command->args; u32 cmd_id = CMD_TO_CMDID(cmd_hdr->cmd); cmd_resp_hdr * resp_hdr = response->header; u32 * resp_args_32 = response->args; u32 resp_index = 0; u32 eth_dev_num = socket_get_eth_dev_num(socket_index); // Set up the response header resp_hdr->cmd = cmd_hdr->cmd; resp_hdr->length = 0; resp_hdr->num_args = 0; // Check Ethernet device number if (eth_dev_num == WARP_IP_UDP_INVALID_ETH_DEVICE) { wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_transport, "Invalid socket index: %d\n", socket_index); return resp_sent; } // Process the command switch(cmd_id){ //--------------------------------------------------------------------- case CMDID_TRANSPORT_PING: { // // Nothing actually needs to be done when receiving the ping command. The framework is going // to respond regardless, which is all the host wants. // } break; //--------------------------------------------------------------------- case CMDID_TRANSPORT_PAYLOAD_SIZE_TEST: { // // Due to packet fragmentation, it is not safe to just return the packet length. We have seen // an issue where the host will send a 1514 byte fragment which results in a payload size of // 1472 and causes the transport to not behave correctly. Therefore, we need to find the // last valid command argument and check that against the packet length. // u32 temp; u32 payload_index; u32 payload_size; u32 payload_num_words; u32 header_size; header_size = (sizeof(transport_header) + sizeof(cmd_resp_hdr)); // Transport / Command headers payload_index = (((warp_ip_udp_buffer *)(command->buffer))->length - sizeof(cmd_resp_hdr)) / 4; // Final index into command args (/4 truncates) // Check the value in the command args to make sure it matches the size_index payload_num_words = Xil_Htonl(cmd_args_32[payload_index - 1]) + 1; // NOTE: Add 1 since the payload is zero indexed payload_size = (payload_num_words * 4) + header_size; temp = ((payload_index * 4) + header_size); // Update the max_pkt_words field if (payload_num_words > eth_devices[eth_dev_num].max_pkt_words) { eth_devices[eth_dev_num].max_pkt_words = payload_num_words; } if (payload_size != temp) { wlan_exp_printf(WLAN_EXP_PRINT_WARNING, print_type_transport, "Payload size mismatch. Value in command args does not match index: %d != %d\n", payload_size, temp); } resp_args_32[resp_index++] = Xil_Ntohl(payload_size); resp_hdr->length += (resp_index * sizeof(resp_args_32)); resp_hdr->num_args = 1; } break; //--------------------------------------------------------------------- case CMDID_TRANSPORT_NODE_GROUP_ID_ADD: { eth_devices[eth_dev_num].info.group_id = (eth_devices[eth_dev_num].info.group_id | Xil_Htonl(cmd_args_32[0])); } break; //--------------------------------------------------------------------- case CMDID_TRANSPORT_NODE_GROUP_ID_CLEAR: { eth_devices[eth_dev_num].info.group_id = (eth_devices[eth_dev_num].info.group_id & ~Xil_Htonl(cmd_args_32[0])); } break; //--------------------------------------------------------------------- default: { wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_transport, "Unknown user command ID: %d\n", cmd_id); } break; } return resp_sent; }
int user_processCmd(const wl_cmdHdr* cmdHdr,const void* cmdArgs, wl_respHdr* respHdr, void* respArgs, void* pktSrc) { //IMPORTANT ENDIAN NOTES: // -cmdHdr is safe to access directly (pre-swapped if needed) // -cmdArgs is *not* pre-swapped, since the framework doesn't know what it is // -respHdr will be swapped by the framework; user code should fill it normally // -respArgs will *not* be swapped by the framework, since only user code knows what it is // Any data added to respArgs by the code below must be endian-safe (swapped on AXI hardware) u32 cmdID; //Cast argument buffers into arrays for easy accessing const u32 *cmdArgs32 = cmdArgs; u32 *respArgs32 = respArgs; /* Example variables for processing user commands const u32 *cmdArgs32 = cmdArgs; u32 *respArgs32 = respArgs; int respIndex = 0; u32 arg0, arg1, result; */ unsigned int respSent = NO_RESP_SENT; cmdID = WL_CMD_TO_CMDID(cmdHdr->cmd); respHdr->cmd = cmdHdr->cmd; respHdr->length = 0; respHdr->numArgs = 0; #ifdef WARP_HW_VER_v3 u32 stringBuffer32[10]; u8 *stringBuffer8 = (u8*)stringBuffer32; int k; u32 readLength; u32 eepromAddrOffset; #endif switch(cmdID) { /* Example user command case SOME_CMD_ID: arg0 = Xil_Ntohl(cmdArgs[0]); arg1 = Xil_Ntohl(cmdArgs[1]); result = do_something_with_args(arg0, arg1); respArgs32[respIndex++] = Xil_Htonl(result); respHdr->length += (respIndex * sizeof(respArgs32)); respHdr->numArgs = respIndex; break; */ #ifdef WARP_HW_VER_v3 case USER_EEPROM_WRITE_STRING: eepromAddrOffset = Xil_Ntohl(cmdArgs32[0]); for( k=0; k<((cmdHdr->length)/sizeof(u32)); k++ ) { stringBuffer32[k] = Xil_Ntohl(cmdArgs32[k+1]); } for( k=0; k<(cmdHdr->length); k++ ) { iic_eeprom_writeByte(EEPROM_BASEADDR,k+eepromAddrOffset,stringBuffer8[k]); } xil_printf("Wrote '%s' to EEPROM\n",stringBuffer8); break; case USER_EEPROM_READ_STRING: eepromAddrOffset = Xil_Ntohl(cmdArgs32[0]); readLength = Xil_Ntohl(cmdArgs32[1]); for( k=0; k<readLength; k++ ) { stringBuffer8[k] = iic_eeprom_readByte(EEPROM_BASEADDR,k+eepromAddrOffset); } xil_printf("Read '%s' from EEPROM\n",stringBuffer8); for( k=0; k<((readLength)/sizeof(u32)); k++ ) { respArgs32[k] = Xil_Htonl(stringBuffer32[k]); } respHdr->length += ((k) * sizeof(respArgs32)); respHdr->numArgs = (k); break; #endif default: xil_printf("Unknown user command ID: %d\n", cmdID); break; } return respSent; }