/** * 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); }
/** * * This function calculates the checksum and returns a 16 bit result. * * @param RxFramePtr is a 16 bit pointer for the data to which checksum * is to be calculated. * @param StartLoc is the starting location of the data from which the * checksum has to be calculated. * @param Length is the number of halfwords(16 bits) to which checksum is * to be calculated. * * @return It returns a 16 bit checksum value. * * @note This can also be used for calculating checksum. The ones * complement of this return value will give the final checksum. * ******************************************************************************/ static u16 CheckSumCalculation(u16 *RxFramePtr, int StartLoc, int Length) { u32 Sum = 0; u16 CheckSum = 0; int Index; /* * Add all the 16 bit data. */ Index = StartLoc; while (Index < (StartLoc + Length)) { Sum = Sum + Xil_Ntohs(*(RxFramePtr + Index)); Index++; } /* * Add upper 16 bits to lower 16 bits. */ CheckSum = Sum; Sum = Sum >> 16; CheckSum = Sum + CheckSum; return CheckSum; }
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; }
/** * * This function processes the received packet and generates the corresponding * reply packets. * * @param InstancePtr is a pointer to the instance of the EmacLite. * * @return None. * * @note This function assumes MAC does not strip padding or CRC. * ******************************************************************************/ static void ProcessRecvFrame(XEmacLite *InstancePtr) { u16 *RxFramePtr; u16 *TxFramePtr; u16 *TempPtr; u16 CheckSum; u32 NextTxBuffBaseAddr; int Index; int PacketType = 0; TxFramePtr = (u16 *)TxFrame; RxFramePtr = (u16 *)RxFrame; /* * Determine the next expected Tx buffer address. */ NextTxBuffBaseAddr = XEmacLite_NextTransmitAddr(InstancePtr); /* * Check the packet type. */ Index = MAC_ADDR_LEN; TempPtr = (u16 *)LocalMacAddr; while (Index--) { if (Xil_Ntohs((*(RxFramePtr + Index)) == BROADCAST_ADDR) && (PacketType != MAC_MATCHED_PACKET)) { PacketType = BROADCAST_PACKET; } else if (Xil_Ntohs((*(RxFramePtr + Index)) == *(TempPtr + Index)) && (PacketType != BROADCAST_PACKET)) { PacketType = MAC_MATCHED_PACKET; } else { PacketType = 0; break; } } /* * Process broadcast packet. */ if (PacketType == BROADCAST_PACKET) { /* * Check for an ARP Packet if so generate a reply. */ if (Xil_Ntohs(*(RxFramePtr + ETHER_PROTO_TYPE_LOC)) == XEL_ETHER_PROTO_TYPE_ARP) { /* * IP address of the local machine. */ TempPtr = (u16 *)LocalIpAddr; /* * Check destination IP address of the packet with * local IP address. */ if ( ((*(RxFramePtr + ARP_REQ_DEST_IP_LOC_1)) == *TempPtr++) && ((*(RxFramePtr + ARP_REQ_DEST_IP_LOC_2)) == *TempPtr++)) { /* * Check ARP packet type(request/reply). */ if (Xil_Ntohs(*(RxFramePtr + ARP_REQ_STATUS_LOC)) == ARP_REQUEST) { /* * Add destination MAC address * to the reply packet (i.e) source * address of the received packet. */ Index = SRC_MAC_ADDR_LOC; while (Index < (SRC_MAC_ADDR_LOC + MAC_ADDR_LEN)) { *TxFramePtr++ = *(RxFramePtr + Index); Index++; } /* * Add source (local) MAC address * to the reply packet. */ Index = 0; TempPtr = (u16 *)LocalMacAddr; while (Index < MAC_ADDR_LEN) { *TxFramePtr++ = *TempPtr++; Index++; } /* * Add Ethernet proto type H/W * type(10/3MBps),H/W address length and * protocol address len (i.e)same as in * the received packet */ Index = ETHER_PROTO_TYPE_LOC; while (Index < (ETHER_PROTO_TYPE_LOC + ETHER_PROTO_TYPE_LEN + ARP_HW_TYPE_LEN + ARP_HW_ADD_LEN + ARP_PROTO_ADD_LEN)) { *TxFramePtr++ = *(RxFramePtr + Index); Index++; } /* * Add ARP reply status to the reply * packet. */ *TxFramePtr++ = Xil_Htons(ARP_REPLY); /* * Add local MAC Address * to the reply packet. */ TempPtr = (u16 *)LocalMacAddr; Index = 0; while (Index < MAC_ADDR_LEN) { *TxFramePtr++ = *TempPtr++; Index++; } /* * Add local IP Address * to the reply packet. */ TempPtr = (u16 *)LocalIpAddr; Index = 0; while (Index < IP_ADDR_LEN) { *TxFramePtr++ = *TempPtr++ ; Index++; } /* * Add Destination MAC Address * to the reply packet from the received * packet. */ Index = SRC_MAC_ADDR_LOC; while (Index < (SRC_MAC_ADDR_LOC + MAC_ADDR_LEN)) { *TxFramePtr++ = *(RxFramePtr + Index); Index++; } /* * Add Destination IP Address * to the reply packet. */ Index = ARP_REQ_SRC_IP_LOC; while (Index < (ARP_REQ_SRC_IP_LOC + IP_ADDR_LEN)) { *TxFramePtr++ = *(RxFramePtr + Index); Index++; } /* * Fill zeros as per protocol. */ Index = 0; while (Index < ARP_ZEROS_LEN) { *TxFramePtr++ = 0x0000; Index++; } /* * Transmit the Reply Packet. */ XEmacLite_Send(InstancePtr, (u8 *)&TxFrame, ARP_PACKET_SIZE); } } } } /* * Process packets whose MAC address is matched. */ if (PacketType == MAC_MATCHED_PACKET) { /* * Check ICMP packet. */ if (Xil_Ntohs(*(RxFramePtr + ETHER_PROTO_TYPE_LOC)) == XEL_ETHER_PROTO_TYPE_IP) { /* * Check the IP header checksum. */ CheckSum = CheckSumCalculation(RxFramePtr, IP_HDR_START_LOC, IP_HDR_LEN); /* * Check the Data field checksum. */ if (CheckSum == CORRECT_CKSUM_VALUE) { CheckSum = CheckSumCalculation(RxFramePtr, ICMP_DATA_START_LOC, ICMP_DATA_FIELD_LEN); if (CheckSum == CORRECT_CKSUM_VALUE) { /* * Add destination address * to the reply packet (i.e)source * address of the received packet. */ Index = SRC_MAC_ADDR_LOC; while (Index < (SRC_MAC_ADDR_LOC + MAC_ADDR_LEN)) { *TxFramePtr++ = *(RxFramePtr + Index); Index++; } /* * Add local MAC address * to the reply packet. */ Index = 0; TempPtr = (u16 *)LocalMacAddr; while (Index < MAC_ADDR_LEN) { *TxFramePtr++ = *TempPtr++; Index++; } /* * Add protocol type * header length and, packet * length(60 Bytes) to the reply packet. */ Index = ETHER_PROTO_TYPE_LOC; while (Index < (ETHER_PROTO_TYPE_LOC + ETHER_PROTO_TYPE_LEN + IP_VERSION_LEN + IP_PACKET_LEN)) { *TxFramePtr++ = *(RxFramePtr + Index); Index++; } /* * Identification field a random number * which is set to IDENT_FIELD_VALUE. */ *TxFramePtr++ = IDENT_FIELD_VALUE; /* * Add fragment type, time to live and * ICM field. It is same as in the * received packet. */ Index = IP_FRAG_FIELD_LOC; while (Index < (IP_FRAG_FIELD_LOC + IP_TTL_ICM_LEN + IP_FRAG_FIELD_LEN)) { *TxFramePtr++ = *(RxFramePtr + Index); Index++; } /* * Checksum first set to 0 and * added in this field later. */ *TxFramePtr++ = 0x0000; /* * Add Source IP address */ Index = 0; TempPtr = (u16 *)LocalIpAddr; while (Index < IP_ADDR_LEN) { *TxFramePtr++ = *TempPtr++; Index++; } /* * Add Destination IP address. */ Index = ICMP_REQ_SRC_IP_LOC; while (Index < (ICMP_REQ_SRC_IP_LOC + IP_ADDR_LEN)) { *TxFramePtr++ = *(RxFramePtr + Index); Index++; } /* * Calculate checksum, and * add it in the appropriate field. */ CheckSum = CheckSumCalculation( (u16 *)TxFrame, IP_HDR_START_LOC, IP_HDR_LEN); CheckSum = ~CheckSum; *(TxFramePtr - IP_CSUM_LOC_BACK) = Xil_Htons(CheckSum); /* * Echo reply status & checksum. */ Index = ICMP_ECHO_FIELD_LOC; while (Index < (ICMP_ECHO_FIELD_LOC + ICMP_ECHO_FIELD_LEN)) { *TxFramePtr++ = 0x0000; Index++; } /* * Add data to buffer which was * received from the packet. */ Index = ICMP_DATA_LOC; while (Index < (ICMP_DATA_LOC + ICMP_DATA_LEN)) { *TxFramePtr++ = (*(RxFramePtr + Index)); Index++; } /* * Generate checksum for the data and * add it in the appropriate field. */ CheckSum = CheckSumCalculation( (u16 *)TxFrame, ICMP_DATA_START_LOC, ICMP_DATA_FIELD_LEN); CheckSum = ~CheckSum; *(TxFramePtr - ICMP_DATA_CSUM_LOC_BACK) = Xil_Htons(CheckSum); /* * Transmit the frame. */ XEmacLite_Send(InstancePtr, (u8 *)&TxFrame, ICMP_PACKET_SIZE); /* * Increment the number of * Ping replies sent. */ NumOfPingReplies++; } } } } }
/** * * This function will process the received packet. This function sends * the echo request packet based on the ARP reply packet. * * @param InstancePtr is a pointer to the instance of the EmacLite. * * @return XST_SUCCESS is returned when an echo reply is received. * Otherwise, XST_FAILURE is returned. * * @note This assumes MAC does not strip padding or CRC. * ******************************************************************************/ static int ProcessRecvFrame(XEmacLite *InstancePtr) { u16 *RxFramePtr; u16 *TempPtr; u16 CheckSum; int Index; int Match = 0; int DataWrong = 0; RxFramePtr = (u16 *)RxFrame; TempPtr = (u16 *)LocalMacAddr; /* * Check Dest Mac address of the packet with the LocalMac address. */ Match = CompareData(RxFramePtr, TempPtr, 0, 0, MAC_ADDR_LEN); if (Match == XST_SUCCESS) { /* * Check ARP type. */ if (Xil_Ntohs(*(RxFramePtr + ETHER_PROTO_TYPE_LOC)) == XEL_ETHER_PROTO_TYPE_ARP ) { /* * Check ARP status. */ if (Xil_Ntohs(*(RxFramePtr + ARP_REQ_STATUS_LOC)) == ARP_REPLY) { /* * Check destination IP address with * packet's source IP address. */ TempPtr = (u16 *)DestIpAddress; Match = CompareData(RxFramePtr, TempPtr, ARP_REQ_SRC_IP_LOC, 0, IP_ADDR_LEN); if (Match == XST_SUCCESS) { /* * Copy src Mac address of the received * packet. */ Index = MAC_ADDR_LEN; TempPtr = (u16 *)DestMacAddr; while (Index--) { *(TempPtr + Index) = *(RxFramePtr + (SRC_MAC_ADDR_LOC + Index)); } /* * Send Echo request packet. */ SendEchoReqFrame(InstancePtr); } } } /* * Check for IP type. */ else if (Xil_Ntohs(*(RxFramePtr + ETHER_PROTO_TYPE_LOC)) == XEL_ETHER_PROTO_TYPE_IP) { /* * Calculate checksum. */ CheckSum = CheckSumCalculation(RxFramePtr, ICMP_DATA_START_LOC, ICMP_DATA_FIELD_LEN); /* * Verify checksum, echo reply, identifier number and * sequence number of the received packet. */ if ((CheckSum == CORRECT_CHECKSUM_VALUE) && (Xil_Ntohs(*(RxFramePtr + ICMP_ECHO_FIELD_LOC)) == ECHO_REPLY) && (Xil_Ntohs(*(RxFramePtr + ICMP_IDEN_FIELD_LOC)) == IDEN_NUM) && (Xil_Ntohs(*(RxFramePtr + (ICMP_SEQ_NO_LOC))) == SeqNum)) { /* * Verify data in the received packet with known * data. */ TempPtr = IcmpData; Match = CompareData(RxFramePtr, TempPtr, ICMP_KNOWN_DATA_LOC, 0, ICMP_KNOWN_DATA_LEN); if (Match == XST_FAILURE) { DataWrong = 1; } } if (DataWrong != 1) { xil_printf("Packet No: %d ", NUM_OF_PING_REQ_PKTS - NumOfPingReqPkts); xil_printf("Seq NO %d Echo Packet received\r\n", SeqNum); return XST_SUCCESS; } } } return XST_FAILURE; }
/** * This function is used to send a message over Ethernet * * @param socket_index - Index of the socket on which to send message * @param to - Pointer to socket address structure to send message * @param buffers - Array of transport buffers to send * @param num_buffers - Number of transport buffers in 'buffers' array * * @return None * * @note This function requires that the first transport buffer in the 'buffers' * array contain the Transport header. * *****************************************************************************/ void transport_send(int socket_index, struct sockaddr * to, warp_ip_udp_buffer ** buffers, u32 num_buffers) { u32 i; int status; transport_header * transport_header_tx; u16 buffer_length = 0; // interrupt_state_t prev_interrupt_state; // Check that we have a valid socket to send a message on if (socket_index == SOCKET_INVALID_SOCKET) { wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_transport, "Invalid socket.\n"); return; } // Initialize the header // NOTE: We require that the first warp_ip_udp_buffer always contain the wl_transport_header // transport_header_tx = (transport_header *)(buffers[0]->data); // Compute the length for (i = 0; i < num_buffers; i++) { buffer_length += buffers[i]->size; } // // NOTE: Through performance testing, we found that it was faster to just manipulate the header // in place vs creating a copy, updating the header and then restoring the copy. // // Make the outgoing transport header endian safe for sending on the network // NOTE: Set the 'length' to the computed value above // transport_header_tx->dest_id = Xil_Htons(transport_header_tx->dest_id); transport_header_tx->src_id = Xil_Htons(transport_header_tx->src_id); transport_header_tx->length = Xil_Htons(buffer_length + WARP_IP_UDP_DELIM_LEN); transport_header_tx->seq_num = Xil_Htons(transport_header_tx->seq_num); transport_header_tx->flags = Xil_Htons(transport_header_tx->flags); // Check the interrupt status; Disable interrupts if enabled // NOTE: This is done inside the Eth send function // prev_interrupt_state = wlan_mac_high_interrupt_stop(); // Send the Ethernet packet status = socket_sendto(socket_index, to, buffers, num_buffers); // Restore interrupts // NOTE: This is done inside the Eth send function // wlan_mac_high_interrupt_restore_state(prev_interrupt_state); // Restore wl_header_tx transport_header_tx->dest_id = Xil_Ntohs(transport_header_tx->dest_id); transport_header_tx->src_id = Xil_Ntohs(transport_header_tx->src_id); transport_header_tx->length = 0; transport_header_tx->seq_num = Xil_Ntohs(transport_header_tx->seq_num); transport_header_tx->flags = Xil_Ntohs(transport_header_tx->flags); // Check that the packet was sent correctly if (status == WARP_IP_UDP_FAILURE) { wlan_exp_printf(WLAN_EXP_PRINT_WARNING, print_type_transport, "Issue sending packet %d to host.\n", transport_header_tx->seq_num); } }
/** * Process the received UDP packet by the transport * * @param eth_dev_num - Ethernet device number * @param socket_index - Index of the socket on which message was received * @param from - Pointer to socket address structure from which message was received * @param recv_buffer - Pointer to transport buffer with received message * @param send_buffer - Pointer to transport buffer for a node response to the message * * @return None * * @note If this packet is a host to node message, then the process_hton_msg_callback * is used to further process the packet. This method will strip off the * Transport header for future packet processing. * *****************************************************************************/ void transport_receive(u32 eth_dev_num, int socket_index, struct sockaddr * from, warp_ip_udp_buffer * recv_buffer, warp_ip_udp_buffer * send_buffer) { int status; u16 dest_id; u16 src_id; u16 seq_num; u16 flags; u32 node_id; u32 group_id; u32 recv_flags = 0; transport_header * transport_header_rx = (transport_header*)(recv_buffer->offset); // Contains entire Ethernet frame; offset points to UDP payload transport_header * transport_header_tx = (transport_header*)(send_buffer->offset); // New buffer for UDP payload // Get the transport headers for the send / receive buffers // NOTE: For the receive buffer, offset points to UDP payload of the Ethernet frame // NOTE: For the send buffer, the offset points to the start of the buffer but since we will use the // UDP header of the socket to transmit the frame, this is effectively the start of the UDP payload // transport_header_rx = (transport_header*)(recv_buffer->offset); transport_header_tx = (transport_header*)(send_buffer->offset); // Update the buffers to account for the transport headers recv_buffer->offset += sizeof(transport_header); recv_buffer->length -= sizeof(transport_header); // Remaining bytes in receive buffer send_buffer->offset += sizeof(transport_header); send_buffer->length += sizeof(transport_header); // Adding bytes to the send buffer send_buffer->size += sizeof(transport_header); // Keep size in sync // Process the data based on the packet type // NOTE: The pkt_type does not need to be endian swapped because it is a u8 // switch(transport_header_rx->pkt_type){ //------------------------------- // Message from the Host to the Node // case PKT_TYPE_HTON_MSG: // Extract values from the received transport header // dest_id = Xil_Ntohs(transport_header_rx->dest_id); src_id = Xil_Ntohs(transport_header_rx->src_id); seq_num = Xil_Ntohs(transport_header_rx->seq_num); flags = Xil_Ntohs(transport_header_rx->flags); node_id = eth_devices[eth_dev_num].node_id; group_id = eth_devices[eth_dev_num].info.group_id; // If this message is not for the given node, then ignore it if((dest_id != node_id) && (dest_id != TRANSPORT_BROADCAST_DEST_ID) && ((dest_id & (0xFF00 | group_id)) == 0)) { return; } // Set the receive flags // [0] - Is the packet broadcast? WLAN_EXP_TRUE / WLAN_EXP_FALSE // if (dest_id == TRANSPORT_BROADCAST_DEST_ID) { recv_flags |= 0x00000001; } // Form outgoing Transport header for any outgoing packet in response to this message // NOTE: The u16/u32 fields here will be endian swapped in transport_send // NOTE: The length field of the header will be set in transport_send // transport_header_tx->dest_id = src_id; transport_header_tx->src_id = node_id; transport_header_tx->pkt_type = PKT_TYPE_NTOH_MSG; transport_header_tx->seq_num = seq_num; transport_header_tx->flags = 0; transport_header_tx->reserved = 0; // Call the callback to further process the recv_buffer status = process_hton_msg_callback(socket_index, from, recv_buffer, recv_flags, send_buffer); if (send_buffer->size != send_buffer->length) { wlan_exp_printf(WLAN_EXP_PRINT_WARNING, print_type_transport, "Send buffer length (%d) does not match size (%d)\n", send_buffer->length, send_buffer->size); } // Based on the status, return a message to the host switch(status) { //------------------------------- // No response has been sent by the node // case NO_RESP_SENT: // Check if the host requires a response from the node if (flags & TRANSPORT_HDR_ROBUST_FLAG) { // Check that the node has something to send to the host if ((send_buffer->length) > sizeof(transport_header)) { transport_send(socket_index, from, &send_buffer, 1); // Send the buffer of data } else { wlan_exp_printf(WLAN_EXP_PRINT_WARNING, print_type_transport, "Host requires response but node has nothing to send.\n"); } } break; //------------------------------- // A response has already been sent by the node // case RESP_SENT: // The transport does not need to do anything else break; default: wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_transport, "Received unknown status for message: %d\n", status); break; } break; default: wlan_exp_printf(WLAN_EXP_PRINT_ERROR, print_type_transport, "Received packet with unknown packet type: %d\n", (transport_header_rx->pkt_type)); break; } }
/** * * This example sends and receives a single packet in loopback mode with * extended VLAN support. * * The transmit frame will have VLAN field populated. * * On receive, HW should pass the VLAN field to receive BDs. * * @param AxiEthernetInstancePtr is a pointer to the instance of the * AxiEthernet component. * @param DmaInstancePtr is a pointer to the instance of the Dma * component. * * @return -XST_SUCCESS to indicate success. * -XST_FAILURE to indicate failure. * * @note Summary of VLAN tags handling in this example * * Frame setup with Tpid1+Cfi1+TxPid => 0x88A83111 * Frame translated to TxTransVid => 0x88A83222 * Frame tagged to Tpid2+Cfi2+TxTagVid => 0x9100C333 + 0x88A83222 * Frame sent and loopbacked. * * Frame stripped with RxStrpVid(0x333) => 0x88A83222 * Frame translated (key:RxVid:0x222) RxTransVid => 0x88A83444 * ******************************************************************************/ int AxiEthernetSgDmaIntrExtVlanExample(XAxiEthernet *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr) { int Status; u32 TxFrameLength; u32 RxFrameLength; int PayloadSize = PAYLOAD_SIZE; u16 Tpid1 = 0x88A8; u16 Tpid2 = 0x9100; u8 Cfi1 = 0x03; u8 Cfi2 = 0x0C; u16 TxVid = 0x0111; u16 TxTransVid = 0x0222; u16 TxTagVid = 0x0333; u16 RxVid = 0x0222; u16 RxTransVid = 0x0444; u16 RxStrpVid = 0x0333; u32 VTagCfiVid; u16 RxCfiVid; u16 RxTpid; u32 RxStatusControlWord; int Valid; XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr); XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); XAxiDma_Bd *BdPtr; XAxiDma_Bd *BdCurPtr; u32 BdSts; /* * Cannot run this example if extended features support is not enabled */ if (!(XAxiEthernet_IsTxVlanTran(AxiEthernetInstancePtr) && XAxiEthernet_IsTxVlanStrp(AxiEthernetInstancePtr) && XAxiEthernet_IsTxVlanTag(AxiEthernetInstancePtr) && XAxiEthernet_IsRxVlanTran(AxiEthernetInstancePtr) && XAxiEthernet_IsRxVlanStrp(AxiEthernetInstancePtr) && XAxiEthernet_IsRxVlanTag(AxiEthernetInstancePtr))) { AxiEthernetUtilErrorTrap("Extended VLAN not available"); return XST_FAILURE; } /* * Clear variables shared with callbacks */ FramesRx = 0; FramesTx = 0; DeviceErrors = 0; memset(RxFrame,0,sizeof(RxFrame)); memset(TxFrame,0,sizeof(TxFrame)); /* * Calculate frame length (not including FCS) plus one VLAN tag */ TxFrameLength = XAE_HDR_VLAN_SIZE + PayloadSize; /* * Setup the packet with one VALN tag = VtagCfiVid to be transmitted * initially. */ VTagCfiVid = (((u32)Tpid1 << 16) | ((u32)Cfi1 << 12) | TxVid); AxiEthernetUtilFrameMemClear(&TxFrame); AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC); AxiEthernetUtilFrameHdrVlanFormatVid(&TxFrame, 0, VTagCfiVid); AxiEthernetUtilFrameHdrVlanFormatType(&TxFrame, PayloadSize, 1); AxiEthernetUtilFrameSetVlanPayloadData(&TxFrame, PayloadSize, 1); /* Intended VLAN setup: * TX translation and tagging. RX stripping and translation. * * Frame setup with Tpid1+Cfi1+TxPid => 0x88A83111 * Frame translated to TxTransVid => 0x88A83222 * Frame tagged to Tpid2+Cfi2+TxTagVid => 0x9100C333 + 0x88A83222 * Frame sent and loopbacked. * * Frame stripped with RxStrpVid(0x333) => 0x88A83222 * Frame translated (key:RxVid:0x222) RxTransVid => 0x88A83444 */ /* Extended VLAN transmit side. Stripping->Translation->Tagging */ /* * Configure VLAN TX tag mode, set to XAE_VTAG_SELECT. */ Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr, XAE_EXT_TXVLAN_TAG_OPTION); Status |= XAxiEthernet_SetVTagMode(AxiEthernetInstancePtr, XAE_VTAG_SELECT, XAE_TX); /* * TX VLAN translation from TxVid to TxTransVid and enable tagging. */ Status |= XAxiEthernet_SetOptions(AxiEthernetInstancePtr, XAE_EXT_TXVLAN_TRAN_OPTION); Status |= XAxiEthernet_SetVidTable(AxiEthernetInstancePtr, TxVid, TxTransVid,0, 1, XAE_TX); /* * TX VLAN tagging is keyed on TxVid to add one additional tag based * on register XAE_TTAG_OFFSET value. */ VTagCfiVid = (((u32)Tpid2 << 16) | ((u32)Cfi2 << 12) | TxTagVid); Status |= XAxiEthernet_SetVTagValue(AxiEthernetInstancePtr, VTagCfiVid, XAE_TX); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting TX VLAN"); return XST_FAILURE; } /* Extended VLAN receive side. Stripping->Translation->Tagging */ /* * Configure VLAN RX strip mode, set to XAE_VSTRP_SELECT. */ Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr, XAE_EXT_RXVLAN_STRP_OPTION); Status |= XAxiEthernet_SetVStripMode(AxiEthernetInstancePtr, XAE_VSTRP_SELECT, XAE_RX); /* * RX VLAN strips based on RxStrpVid and enable stripping. */ Status |= XAxiEthernet_SetVidTable(AxiEthernetInstancePtr, RxStrpVid, RxStrpVid, 1, 0, XAE_RX); /* * RX VLAN translation from RxVid to RxTransVid only. */ Status |= XAxiEthernet_SetOptions(AxiEthernetInstancePtr, XAE_EXT_RXVLAN_TRAN_OPTION); Status |= XAxiEthernet_SetVidTable(AxiEthernetInstancePtr, RxVid, RxTransVid, 0, 0, XAE_RX); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting RX VLAN"); return XST_FAILURE; } /* Configure VLAN TPIDs for HW to recognize. */ Status = XAxiEthernet_SetTpid(AxiEthernetInstancePtr, Tpid1, 0); Status |= XAxiEthernet_SetTpid(AxiEthernetInstancePtr, Tpid2, 1); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting TPIDs"); return XST_FAILURE; } /* * Flush the TX frame before giving it to DMA TX channel to transmit. */ Xil_DCacheFlushRange((u32)&TxFrame, TxFrameLength); /* * Clear out receive packet memory area */ AxiEthernetUtilFrameMemClear(&RxFrame); /* * Invalidate the RX frame before giving it to DMA RX channel to * receive data. */ Xil_DCacheInvalidateRange((u32)&RxFrame, TxFrameLength + 4); /* * Interrupt coalescing parameters are set to their default settings * which is to interrupt the processor after every frame has been * processed by the DMA engine. */ Status = XAxiDma_BdRingSetCoalesce(TxRingPtr, 1, 1); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting coalescing for transmit"); return XST_FAILURE; } Status = XAxiDma_BdRingSetCoalesce(RxRingPtr, 1, 1); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting coalescing for recv"); return XST_FAILURE; } /* * Make sure Tx and Rx are enabled */ Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr, XAE_RECEIVER_ENABLE_OPTION | XAE_TRANSMITTER_ENABLE_OPTION ); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting options"); return XST_FAILURE; } Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr, XAE_JUMBO_OPTION); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error setting options"); return XST_FAILURE; } /* * Start the AxiEthernet and enable its ERROR interrupts */ XAxiEthernet_Start(AxiEthernetInstancePtr); XAxiEthernet_IntEnable(&AxiEthernetInstance, XAE_INT_RECV_ERROR_MASK); /* * Enable DMA receive related interrupts */ XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); /* * Allocate 1 RxBD. */ Status = XAxiDma_BdRingAlloc(RxRingPtr, 1, &BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error allocating RxBD"); return XST_FAILURE; } /* * Setup the BD. */ XAxiDma_BdSetBufAddr(BdPtr, (u32)&RxFrame); #ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL XAxiDma_BdSetLength(BdPtr, sizeof(RxFrame)); #else XAxiDma_BdSetLength(BdPtr, sizeof(RxFrame), RxRingPtr->MaxTransferLen); #endif XAxiDma_BdSetCtrl(BdPtr, 0); /* * Enqueue to HW */ Status = XAxiDma_BdRingToHw(RxRingPtr, 1, BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error committing RxBD to HW"); return XST_FAILURE; } /* * Start DMA RX channel. Now it's ready to receive data. */ Status = XAxiDma_BdRingStart(RxRingPtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Enable DMA transmit related interrupts */ XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); /* * Allocate 1 TxBD */ Status = XAxiDma_BdRingAlloc(TxRingPtr, 1, &BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error allocating TxBD"); return XST_FAILURE; } /* * Setup the TxBD */ XAxiDma_BdSetBufAddr(BdPtr, (u32)&TxFrame); #ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL XAxiDma_BdSetLength(BdPtr, TxFrameLength); #else XAxiDma_BdSetLength(BdPtr, TxFrameLength, TxRingPtr->MaxTransferLen); #endif XAxiDma_BdSetCtrl(BdPtr, XAXIDMA_BD_CTRL_TXSOF_MASK | XAXIDMA_BD_CTRL_TXEOF_MASK); /* * Enqueue to HW */ Status = XAxiDma_BdRingToHw(TxRingPtr, 1, BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error committing TxBD to HW"); return XST_FAILURE; } /* * Start DMA TX channel. Transmission starts at once. */ Status = XAxiDma_BdRingStart(TxRingPtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Wait for transmission to complete */ while (!FramesTx); /* * Now that the frame has been sent, post process our TxBDs. * Since we have only submitted 2 to HW, then there should be only 2 * ready for post processing. */ if (XAxiDma_BdRingFromHw(TxRingPtr, 1, &BdPtr) == 0) { AxiEthernetUtilErrorTrap("TxBDs were not ready for post processing"); return XST_FAILURE; } /* * Examine the TxBDs. * * There isn't much to do. The only thing to check would be DMA * exception bits. But this would also be caught in the error handler. * So we just return these BDs to the free list */ Status = XAxiDma_BdRingFree(TxRingPtr, 1, BdPtr); if (Status != XST_SUCCESS) { AxiEthernetUtilErrorTrap("Error freeing up TxBDs"); return XST_FAILURE; } /* * Wait for Rx indication */ while (!FramesRx); /* * Now that the frame has been received, post process our RxBD. * Since we have only submitted 1 to HW, then there should be only 1 * ready for post processing. */ if (XAxiDma_BdRingFromHw(RxRingPtr, 1, &BdPtr) == 0) { AxiEthernetUtilErrorTrap("RxBD was not ready for post processing"); return XST_FAILURE; } BdCurPtr = BdPtr; BdSts = XAxiDma_BdGetSts(BdCurPtr); if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) || (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) { AxiEthernetUtilErrorTrap("Rx Error"); return XST_FAILURE; } else { RxFrameLength = (XAxiDma_BdRead(BdCurPtr,XAXIDMA_BD_USR4_OFFSET)) & 0x0000FFFF; } /* Expected RX TPID+CFI+VID !!! */ VTagCfiVid = (((u32)Tpid2 << 16) | ((u32)Cfi2 << 12) | RxStrpVid); /* Check on the VLAN CFI and VID */ RxStatusControlWord = XAxiDma_BdGetAppWord(BdPtr, BD_VLAN_VID_OFFSET, &Valid); if(Valid) { RxCfiVid = RxStatusControlWord >> 16; RxCfiVid = Xil_Ntohs(RxCfiVid); if(RxCfiVid != (VTagCfiVid & 0x0000FFFF)) { AxiEthernetUtilErrorTrap("VLAN CFI and VID mismatch\n"); return XST_FAILURE; } } else {