linux/drivers/net/wireless/libertas/rx.c
<<
>>
Prefs
   1/**
   2  * This file contains the handling of RX in wlan driver.
   3  */
   4#include <linux/etherdevice.h>
   5#include <linux/types.h>
   6
   7#include "hostcmd.h"
   8#include "radiotap.h"
   9#include "decl.h"
  10#include "dev.h"
  11#include "wext.h"
  12
  13struct eth803hdr {
  14        u8 dest_addr[6];
  15        u8 src_addr[6];
  16        u16 h803_len;
  17} __attribute__ ((packed));
  18
  19struct rfc1042hdr {
  20        u8 llc_dsap;
  21        u8 llc_ssap;
  22        u8 llc_ctrl;
  23        u8 snap_oui[3];
  24        u16 snap_type;
  25} __attribute__ ((packed));
  26
  27struct rxpackethdr {
  28        struct rxpd rx_pd;
  29        struct eth803hdr eth803_hdr;
  30        struct rfc1042hdr rfc1042_hdr;
  31} __attribute__ ((packed));
  32
  33struct rx80211packethdr {
  34        struct rxpd rx_pd;
  35        void *eth80211_hdr;
  36} __attribute__ ((packed));
  37
  38static int process_rxed_802_11_packet(struct lbs_private *priv,
  39        struct sk_buff *skb);
  40
  41/**
  42 *  @brief This function computes the avgSNR .
  43 *
  44 *  @param priv    A pointer to struct lbs_private structure
  45 *  @return        avgSNR
  46 */
  47static u8 lbs_getavgsnr(struct lbs_private *priv)
  48{
  49        u8 i;
  50        u16 temp = 0;
  51        if (priv->numSNRNF == 0)
  52                return 0;
  53        for (i = 0; i < priv->numSNRNF; i++)
  54                temp += priv->rawSNR[i];
  55        return (u8) (temp / priv->numSNRNF);
  56
  57}
  58
  59/**
  60 *  @brief This function computes the AvgNF
  61 *
  62 *  @param priv    A pointer to struct lbs_private structure
  63 *  @return        AvgNF
  64 */
  65static u8 lbs_getavgnf(struct lbs_private *priv)
  66{
  67        u8 i;
  68        u16 temp = 0;
  69        if (priv->numSNRNF == 0)
  70                return 0;
  71        for (i = 0; i < priv->numSNRNF; i++)
  72                temp += priv->rawNF[i];
  73        return (u8) (temp / priv->numSNRNF);
  74
  75}
  76
  77/**
  78 *  @brief This function save the raw SNR/NF to our internel buffer
  79 *
  80 *  @param priv    A pointer to struct lbs_private structure
  81 *  @param prxpd   A pointer to rxpd structure of received packet
  82 *  @return        n/a
  83 */
  84static void lbs_save_rawSNRNF(struct lbs_private *priv, struct rxpd *p_rx_pd)
  85{
  86        if (priv->numSNRNF < DEFAULT_DATA_AVG_FACTOR)
  87                priv->numSNRNF++;
  88        priv->rawSNR[priv->nextSNRNF] = p_rx_pd->snr;
  89        priv->rawNF[priv->nextSNRNF] = p_rx_pd->nf;
  90        priv->nextSNRNF++;
  91        if (priv->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR)
  92                priv->nextSNRNF = 0;
  93        return;
  94}
  95
  96/**
  97 *  @brief This function computes the RSSI in received packet.
  98 *
  99 *  @param priv    A pointer to struct lbs_private structure
 100 *  @param prxpd   A pointer to rxpd structure of received packet
 101 *  @return        n/a
 102 */
 103static void lbs_compute_rssi(struct lbs_private *priv, struct rxpd *p_rx_pd)
 104{
 105
 106        lbs_deb_enter(LBS_DEB_RX);
 107
 108        lbs_deb_rx("rxpd: SNR %d, NF %d\n", p_rx_pd->snr, p_rx_pd->nf);
 109        lbs_deb_rx("before computing SNR: SNR-avg = %d, NF-avg = %d\n",
 110               priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
 111               priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
 112
 113        priv->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr;
 114        priv->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
 115        lbs_save_rawSNRNF(priv, p_rx_pd);
 116
 117        priv->SNR[TYPE_RXPD][TYPE_AVG] = lbs_getavgsnr(priv) * AVG_SCALE;
 118        priv->NF[TYPE_RXPD][TYPE_AVG] = lbs_getavgnf(priv) * AVG_SCALE;
 119        lbs_deb_rx("after computing SNR: SNR-avg = %d, NF-avg = %d\n",
 120               priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
 121               priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
 122
 123        priv->RSSI[TYPE_RXPD][TYPE_NOAVG] =
 124            CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_NOAVG],
 125                     priv->NF[TYPE_RXPD][TYPE_NOAVG]);
 126
 127        priv->RSSI[TYPE_RXPD][TYPE_AVG] =
 128            CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
 129                     priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
 130
 131        lbs_deb_leave(LBS_DEB_RX);
 132}
 133
 134/**
 135 *  @brief This function processes received packet and forwards it
 136 *  to kernel/upper layer
 137 *
 138 *  @param priv    A pointer to struct lbs_private
 139 *  @param skb     A pointer to skb which includes the received packet
 140 *  @return        0 or -1
 141 */
 142int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
 143{
 144        int ret = 0;
 145        struct net_device *dev = priv->dev;
 146        struct rxpackethdr *p_rx_pkt;
 147        struct rxpd *p_rx_pd;
 148        int hdrchop;
 149        struct ethhdr *p_ethhdr;
 150        const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
 151
 152        lbs_deb_enter(LBS_DEB_RX);
 153
 154        BUG_ON(!skb);
 155
 156        skb->ip_summed = CHECKSUM_NONE;
 157
 158        if (priv->monitormode)
 159                return process_rxed_802_11_packet(priv, skb);
 160
 161        p_rx_pkt = (struct rxpackethdr *) skb->data;
 162        p_rx_pd = &p_rx_pkt->rx_pd;
 163        if (priv->mesh_dev && (p_rx_pd->rx_control & RxPD_MESH_FRAME))
 164                dev = priv->mesh_dev;
 165
 166        lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data,
 167                 min_t(unsigned int, skb->len, 100));
 168
 169        if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
 170                lbs_deb_rx("rx err: frame received with bad length\n");
 171                priv->stats.rx_length_errors++;
 172                ret = 0;
 173                goto done;
 174        }
 175
 176        /*
 177         * Check rxpd status and update 802.3 stat,
 178         */
 179        if (!(p_rx_pd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) {
 180                lbs_deb_rx("rx err: frame received with bad status\n");
 181                lbs_pr_alert("rxpd not ok\n");
 182                priv->stats.rx_errors++;
 183                ret = 0;
 184                goto done;
 185        }
 186
 187        lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n",
 188               skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
 189
 190        lbs_deb_hex(LBS_DEB_RX, "RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
 191                sizeof(p_rx_pkt->eth803_hdr.dest_addr));
 192        lbs_deb_hex(LBS_DEB_RX, "RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
 193                sizeof(p_rx_pkt->eth803_hdr.src_addr));
 194
 195        if (memcmp(&p_rx_pkt->rfc1042_hdr,
 196                   rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
 197                /*
 198                 *  Replace the 803 header and rfc1042 header (llc/snap) with an
 199                 *    EthernetII header, keep the src/dst and snap_type (ethertype)
 200                 *
 201                 *  The firmware only passes up SNAP frames converting
 202                 *    all RX Data from 802.11 to 802.2/LLC/SNAP frames.
 203                 *
 204                 *  To create the Ethernet II, just move the src, dst address right
 205                 *    before the snap_type.
 206                 */
 207                p_ethhdr = (struct ethhdr *)
 208                    ((u8 *) & p_rx_pkt->eth803_hdr
 209                     + sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr)
 210                     - sizeof(p_rx_pkt->eth803_hdr.dest_addr)
 211                     - sizeof(p_rx_pkt->eth803_hdr.src_addr)
 212                     - sizeof(p_rx_pkt->rfc1042_hdr.snap_type));
 213
 214                memcpy(p_ethhdr->h_source, p_rx_pkt->eth803_hdr.src_addr,
 215                       sizeof(p_ethhdr->h_source));
 216                memcpy(p_ethhdr->h_dest, p_rx_pkt->eth803_hdr.dest_addr,
 217                       sizeof(p_ethhdr->h_dest));
 218
 219                /* Chop off the rxpd + the excess memory from the 802.2/llc/snap header
 220                 *   that was removed
 221                 */
 222                hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt;
 223        } else {
 224                lbs_deb_hex(LBS_DEB_RX, "RX Data: LLC/SNAP",
 225                        (u8 *) & p_rx_pkt->rfc1042_hdr,
 226                        sizeof(p_rx_pkt->rfc1042_hdr));
 227
 228                /* Chop off the rxpd */
 229                hdrchop = (u8 *) & p_rx_pkt->eth803_hdr - (u8 *) p_rx_pkt;
 230        }
 231
 232        /* Chop off the leading header bytes so the skb points to the start of
 233         *   either the reconstructed EthII frame or the 802.2/llc/snap frame
 234         */
 235        skb_pull(skb, hdrchop);
 236
 237        /* Take the data rate from the rxpd structure
 238         * only if the rate is auto
 239         */
 240        if (priv->enablehwauto)
 241                priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);
 242
 243        lbs_compute_rssi(priv, p_rx_pd);
 244
 245        lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
 246        priv->stats.rx_bytes += skb->len;
 247        priv->stats.rx_packets++;
 248
 249        skb->protocol = eth_type_trans(skb, dev);
 250        if (in_interrupt())
 251                netif_rx(skb);
 252        else
 253                netif_rx_ni(skb);
 254
 255        ret = 0;
 256done:
 257        lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret);
 258        return ret;
 259}
 260EXPORT_SYMBOL_GPL(lbs_process_rxed_packet);
 261
 262/**
 263 *  @brief This function converts Tx/Rx rates from the Marvell WLAN format
 264 *  (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s)
 265 *
 266 *  @param rate    Input rate
 267 *  @return        Output Rate (0 if invalid)
 268 */
 269static u8 convert_mv_rate_to_radiotap(u8 rate)
 270{
 271        switch (rate) {
 272        case 0:         /*   1 Mbps */
 273                return 2;
 274        case 1:         /*   2 Mbps */
 275                return 4;
 276        case 2:         /* 5.5 Mbps */
 277                return 11;
 278        case 3:         /*  11 Mbps */
 279                return 22;
 280        /* case 4: reserved */
 281        case 5:         /*   6 Mbps */
 282                return 12;
 283        case 6:         /*   9 Mbps */
 284                return 18;
 285        case 7:         /*  12 Mbps */
 286                return 24;
 287        case 8:         /*  18 Mbps */
 288                return 36;
 289        case 9:         /*  24 Mbps */
 290                return 48;
 291        case 10:                /*  36 Mbps */
 292                return 72;
 293        case 11:                /*  48 Mbps */
 294                return 96;
 295        case 12:                /*  54 Mbps */
 296                return 108;
 297        }
 298        lbs_pr_alert("Invalid Marvell WLAN rate %i\n", rate);
 299        return 0;
 300}
 301
 302/**
 303 *  @brief This function processes a received 802.11 packet and forwards it
 304 *  to kernel/upper layer
 305 *
 306 *  @param priv    A pointer to struct lbs_private
 307 *  @param skb     A pointer to skb which includes the received packet
 308 *  @return        0 or -1
 309 */
 310static int process_rxed_802_11_packet(struct lbs_private *priv,
 311        struct sk_buff *skb)
 312{
 313        int ret = 0;
 314
 315        struct rx80211packethdr *p_rx_pkt;
 316        struct rxpd *prxpd;
 317        struct rx_radiotap_hdr radiotap_hdr;
 318        struct rx_radiotap_hdr *pradiotap_hdr;
 319
 320        lbs_deb_enter(LBS_DEB_RX);
 321
 322        p_rx_pkt = (struct rx80211packethdr *) skb->data;
 323        prxpd = &p_rx_pkt->rx_pd;
 324
 325        // lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
 326
 327        if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
 328                lbs_deb_rx("rx err: frame received with bad length\n");
 329                priv->stats.rx_length_errors++;
 330                ret = -EINVAL;
 331                kfree_skb(skb);
 332                goto done;
 333        }
 334
 335        /*
 336         * Check rxpd status and update 802.3 stat,
 337         */
 338        if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) {
 339                //lbs_deb_rx("rx err: frame received with bad status\n");
 340                priv->stats.rx_errors++;
 341        }
 342
 343        lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n",
 344               skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
 345
 346        /* create the exported radio header */
 347
 348        /* radiotap header */
 349        radiotap_hdr.hdr.it_version = 0;
 350        /* XXX must check this value for pad */
 351        radiotap_hdr.hdr.it_pad = 0;
 352        radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr));
 353        radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT);
 354        /* unknown values */
 355        radiotap_hdr.flags = 0;
 356        radiotap_hdr.chan_freq = 0;
 357        radiotap_hdr.chan_flags = 0;
 358        radiotap_hdr.antenna = 0;
 359        /* known values */
 360        radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate);
 361        /* XXX must check no carryout */
 362        radiotap_hdr.antsignal = prxpd->snr + prxpd->nf;
 363        radiotap_hdr.rx_flags = 0;
 364        if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK)))
 365                radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS;
 366        //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18);
 367
 368        /* chop the rxpd */
 369        skb_pull(skb, sizeof(struct rxpd));
 370
 371        /* add space for the new radio header */
 372        if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) &&
 373            pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, GFP_ATOMIC)) {
 374                lbs_pr_alert("%s: couldn't pskb_expand_head\n", __func__);
 375                ret = -ENOMEM;
 376                kfree_skb(skb);
 377                goto done;
 378        }
 379
 380        pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr));
 381        memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr));
 382
 383        /* Take the data rate from the rxpd structure
 384         * only if the rate is auto
 385         */
 386        if (priv->enablehwauto)
 387                priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);
 388
 389        lbs_compute_rssi(priv, prxpd);
 390
 391        lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
 392        priv->stats.rx_bytes += skb->len;
 393        priv->stats.rx_packets++;
 394
 395        skb->protocol = eth_type_trans(skb, priv->rtap_net_dev);
 396        netif_rx(skb);
 397
 398        ret = 0;
 399
 400done:
 401        lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret);
 402        return ret;
 403}
 404
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.