/**
 *  @brief Get wireless statistics
 *
 *  @param dev          A pointer to net_device structure
 *
 *  @return             A pointer to iw_statistics buf
 */
struct iw_statistics *
woal_get_uap_wireless_stats(struct net_device *dev)
{
	moal_private *priv = (moal_private *) netdev_priv(dev);
	t_u16 wait_option = MOAL_NO_WAIT;

	ENTER();

	/*
	 * Since schedule() is not allowed from an atomic context
	 * such as when dev_base_lock for netdevices is acquired
	 * for reading/writing in kernel before this call, HostCmd
	 * is issued in non-blocking way in such contexts and
	 * blocking in other cases.
	 */
	if (write_can_lock(&dev_base_lock)
	    && (!in_atomic() || current->exit_state))
		wait_option = MOAL_WSTATS_WAIT;

	priv->w_stats.qual.qual = 0;
	priv->w_stats.qual.level = 0;
	priv->w_stats.discard.code = 0;
	priv->w_stats.status = IW_MODE_MASTER;
	woal_uap_get_stats(priv, wait_option, NULL);

	LEAVE();
	return &priv->w_stats;
}
/**
 *  @brief Get wireless statistics
 *
 *  @param dev          A pointer to net_device structure
 *
 *  @return             A pointer to iw_statistics buf
 */
struct iw_statistics *
woal_get_uap_wireless_stats(struct net_device *dev)
{
    moal_private *priv = (moal_private *) netdev_priv(dev);
    t_u16 wait_option = MOAL_IOCTL_WAIT;
    mlan_ds_uap_stats ustats;

    ENTER();

    memset(&ustats, 0, sizeof(mlan_ds_uap_stats));
    woal_uap_get_stats(priv, wait_option, &ustats);
    w_stats.status = IW_MODE_MASTER;
    w_stats.discard.retries = ustats.failed_count;
    w_stats.qual.qual = 0;
    w_stats.discard.code = 0;
    w_stats.discard.fragment = ustats.fcs_error_count;
    w_stats.discard.retries = ustats.retry_count;
    w_stats.discard.misc = ustats.ack_failure_count;

    LEAVE();
    return &w_stats;
}
/** 
 *  @brief Proc read function for info
 *
 *  @param page	   Pointer to buffer
 *  @param start   Read data starting position
 *  @param offset  Offset
 *  @param count   Counter 
 *  @param eof     End of file flag
 *  @param data    Data to output
 *
 *  @return 	   Number of output data
 */
static int
woal_info_proc_read(char *page, char **start, off_t offset,
                    int count, int *eof, void *data)
{
    char *p = page;
    struct net_device *netdev = data;
    char fmt[64];
    moal_private *priv = (moal_private *) netdev_priv(netdev);
#ifdef STA_SUPPORT
    int i = 0;
    moal_handle *handle = priv->phandle;
    mlan_bss_info info;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
    struct dev_mc_list *mcptr = netdev->mc_list;
    int mc_count = netdev->mc_count;
#else
    struct netdev_hw_addr *mcptr = NULL;
    int mc_count = netdev_mc_count(netdev);
#endif /* < 2.6.35 */
#endif
#ifdef UAP_SUPPORT
    mlan_ds_uap_stats ustats;
#endif

    if (offset) {
        *eof = 1;
        goto exit;
    }
#ifdef UAP_SUPPORT
    if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
        p += sprintf(p, "driver_name = " "\"uap\"\n");
        woal_uap_get_version(priv, fmt, sizeof(fmt) - 1);
        if (MLAN_STATUS_SUCCESS !=
            woal_uap_get_stats(priv, MOAL_PROC_WAIT, &ustats)) {
            *eof = 1;
            goto exit;
        }
    }
#endif /* UAP_SUPPORT */
#ifdef STA_SUPPORT
    if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
        woal_get_version(handle, fmt, sizeof(fmt) - 1);
        memset(&info, 0, sizeof(info));
        if (MLAN_STATUS_SUCCESS !=
            woal_get_bss_info(priv, MOAL_PROC_WAIT, &info)) {
            *eof = 1;
            goto exit;
        }
        p += sprintf(p, "driver_name = " "\"wlan\"\n");
    }
#endif
    p += sprintf(p, "driver_version = %s", fmt);
    p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name);
#ifdef STA_SUPPORT
    if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
        p += sprintf(p, "bss_mode=\"%s\"\n", szModes[info.bss_mode]);
#endif
    p += sprintf(p, "media_state=\"%s\"\n",
                 ((priv->media_connected ==
                   MFALSE) ? "Disconnected" : "Connected"));
    p += sprintf(p, "mac_address=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
                 netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
                 netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
#ifdef STA_SUPPORT
    if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
        p += sprintf(p, "multicast_count=\"%d\"\n", mc_count);
        p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid);
        p += sprintf(p, "bssid=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
                     info.bssid[0], info.bssid[1],
                     info.bssid[2], info.bssid[3],
                     info.bssid[4], info.bssid[5]);
        p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan);
        p += sprintf(p, "region_code = \"%02x\"\n", (t_u8) info.region_code);

        /* 
         * Put out the multicast list 
         */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
        for (i = 0; i < netdev->mc_count; i++) {
            p += sprintf(p,
                         "multicast_address[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
                         i,
                         mcptr->dmi_addr[0], mcptr->dmi_addr[1],
                         mcptr->dmi_addr[2], mcptr->dmi_addr[3],
                         mcptr->dmi_addr[4], mcptr->dmi_addr[5]);

            mcptr = mcptr->next;
        }
#else
        netdev_for_each_mc_addr(mcptr, netdev)
            p += sprintf(p,
                         "multicast_address[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
                         i++,
                         mcptr->addr[0], mcptr->addr[1],
                         mcptr->addr[2], mcptr->addr[3],
                         mcptr->addr[4], mcptr->addr[5]);
#endif /* < 2.6.35 */
    }
#endif
    p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
    p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
    p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
    p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
    p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
    p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
    p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
    p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
    p += sprintf(p, "carrier %s\n",
                 ((netif_carrier_ok(priv->netdev)) ? "on" : "off"));
    p += sprintf(p, "tx queue %s\n",
                 ((netif_queue_stopped(priv->netdev)) ? "stopped" : "started"));
#ifdef UAP_SUPPORT
    if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
        p += sprintf(p, "tkip_mic_failures = %lu\n", ustats.tkip_mic_failures);
        p += sprintf(p, "ccmp_decrypt_errors = %lu\n",
                     ustats.ccmp_decrypt_errors);
        p += sprintf(p, "wep_undecryptable_count = %lu\n",
                     ustats.wep_undecryptable_count);
        p += sprintf(p, "wep_icv_error_count = %lu\n",
                     ustats.wep_icv_error_count);
        p += sprintf(p, "decrypt_failure_count = %lu\n",
                     ustats.decrypt_failure_count);
        p += sprintf(p, "mcast_tx_count = %lu\n", ustats.mcast_tx_count);
        p += sprintf(p, "failed_count = %lu\n", ustats.failed_count);
        p += sprintf(p, "retry_count = %lu\n", ustats.retry_count);
        p += sprintf(p, "multiple_retry_count = %lu\n",
                     ustats.multi_retry_count);
        p += sprintf(p, "frame_duplicate_count = %lu\n",
                     ustats.frame_dup_count);
        p += sprintf(p, "rts_success_count = %lu\n", ustats.rts_success_count);
        p += sprintf(p, "rts_failure_count = %lu\n", ustats.rts_failure_count);
        p += sprintf(p, "ack_failure_count = %lu\n", ustats.ack_failure_count);
        p += sprintf(p, "rx_fragment_count = %lu\n", ustats.rx_fragment_count);
        p += sprintf(p, "mcast_rx_frame_count = %lu\n",
                     ustats.mcast_rx_frame_count);
        p += sprintf(p, "fcs_error_count = %lu\n", ustats.fcs_error_count);
        p += sprintf(p, "tx_frame_count = %lu\n", ustats.tx_frame_count);
        p += sprintf(p, "rsna_tkip_cm_invoked = %lu\n",
                     ustats.rsna_tkip_cm_invoked);
        p += sprintf(p, "rsna_4way_hshk_failures = %lu\n",
                     ustats.rsna_4way_hshk_failures);
    }
#endif /* UAP_SUPPORT */
  exit:
    return (p - page);
}