void purge_queue(u16 queue_sel){
	packet_bd_list dequeue;
	u32            num_queued;

	num_queued = queue_num_queued(queue_sel);

	if( num_queued > 0 ){
		xil_printf("purging %d packets from queue for queue ID %d\n", num_queued, queue_sel);
		dequeue_from_beginning(&dequeue, queue_sel, 1);
		queue_checkin(&dequeue);
	}
}
void ApiControladorDeVuelo::enviar_mensaje_to_checkin(int num_puesto_checkin, int num_zona, bool iniciar_checkin) {
   tMeansajeCheckin msg_checkin;
   msg_checkin.mtype = num_puesto_checkin;
   msg_checkin.iniciar_checkin = iniciar_checkin;
   msg_checkin.num_vuelo = num_vuelo;
   msg_checkin.num_zona = num_zona;
   char path_to_control_checkin_lock[128];
   snprintf(path_to_control_checkin_lock, 128, "%s%s", path_to_locks.c_str(), PATH_COLA_CONTROL_CHECKIN);

   MessageQueue queue_checkin(path_to_control_checkin_lock, 0);
   queue_checkin.push(&msg_checkin, sizeof(tMeansajeCheckin)-sizeof(long));
}
int wlan_mac_poll_tx_queue(u16 queue_sel){
	int return_value = 0;;

	packet_bd_list dequeue;
	packet_bd* tx_queue;

	dequeue_from_beginning(&dequeue, queue_sel,1);

	if(dequeue.length == 1){
		return_value = 1;
		tx_queue = dequeue.first;
		mpdu_transmit(tx_queue);
		queue_checkin(&dequeue);
		wlan_eth_dma_update();
	}

	return return_value;
}
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(&ETH_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;
}