Add in IWSPY support, courtesy of Josef Kriegl

That patch got morphed into the beginnings of an overhaul of the rx
frame representation, with OOB metadata being passed with each frame to
p80211.  Eventually there will only be one rx path in the NSD, and
p80211conv_* will be the only thing to care about how it goes out to
userland (eg sniff headers, etc)
This commit is contained in:
solomon 2004-05-04 15:11:41 +00:00
parent 9b87e2e340
commit 603ae70f9a
11 changed files with 398 additions and 106 deletions

View File

@ -42,6 +42,14 @@
*
* --------------------------------------------------------------------
-pre21
- Add a per frame rx structure for OOB data to be passed to p80211
This is a step in the right direction for a major overhaul of
internal frame representation. The prism2 driver shouldn't care
about sniff headers or any of that crap; it should always pass
everything to p80211 (via this metadata) and the p80211conv_*
functions should do that work. It's also needed to eventually
support different encryption types.
- Added in beginnings of IWSPY support via patch from Josef Kriegl
- Primary/Secondary firmware (finally) bundled with the driver.
- Convert to newer 2.6 module parameter code.
- Fix an inverted test in GIWENCODE wireless extension (Shiro Ninomiya)

1
THANKS
View File

@ -119,6 +119,7 @@ Francesco Bochicchio <bockman@virgilio.it>
Federico Pellegrin <fede.evol@virgilio.it>
Nemanja Jakovljevic <nemanjaj@sezampro.yu>
Shiro Ninomiya <shiro@margi.com>
Josef Kriegl <jkriegl@sensoria.com>
[Many, many more. If I've overlooked you and you want to be listed here,
send me e-mail and I'll fix it. I _know_ a bunch of linux-wlan contributors

View File

@ -72,6 +72,42 @@
/*================================================================*/
/* Macros */
#define P80211_FRMMETA_MAGIC 0x802110
#define P80211SKB_FRMMETA(s) \
(((((p80211_frmmeta_t*)((s)->cb))->magic)==P80211_FRMMETA_MAGIC) ? \
((p80211_frmmeta_t*)((s)->cb)) : \
(NULL))
#define P80211SKB_RXMETA(s) \
(P80211SKB_FRMMETA((s)) ? P80211SKB_FRMMETA((s))->rx : ((p80211_rxmeta_t*)(NULL)))
typedef struct p80211_rxmeta
{
struct wlandevice *wlandev;
UINT64 mactime; /* Hi-rez MAC-supplied time value */
UINT64 hosttime; /* Best-rez host supplied time value */
UINT rxrate; /* Receive data rate in 100kbps */
UINT priority; /* 0-15, 0=contention, 6=CF */
INT signal; /* An SSI, see p80211netdev.h */
INT noise; /* An SSI, see p80211netdev.h */
UINT channel; /* Receive channel (mostly for snifs) */
UINT preamble; /* P80211ENUM_preambletype_* */
UINT encoding; /* P80211ENUM_encoding_* */
} p80211_rxmeta_t;
typedef struct p80211_frmmeta
{
UINT magic;
p80211_rxmeta_t *rx;
} p80211_frmmeta_t;
void p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb);
int p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb);
void p80211skb_rxmeta_detach(struct sk_buff *skb);
/*================================================================*/
/* Types */

View File

@ -256,4 +256,42 @@ typedef union p80211_hdr
void p802addr_to_str( char *buf, UINT8 *addr);
/* Frame and header lenght macros */
#define WLAN_CTL_FRAMELEN(fstype) (\
(fstype) == WLAN_FSTYPE_PSPOLL ? 20 : \
(fstype) == WLAN_FSTYPE_RTS ? 20 : \
(fstype) == WLAN_FSTYPE_CTS ? 14 : \
(fstype) == WLAN_FSTYPE_ACK ? 14 : \
(fstype) == WLAN_FSTYPE_CFEND ? 20 : \
(fstype) == WLAN_FSTYPE_CFENDCFACK ? 20 : 0)
#define WLAN_FCS_LEN 4
/* ftcl in HOST order */
inline static UINT16 p80211_headerlen(UINT16 fctl)
{
UINT16 hdrlen = 0;
switch ( WLAN_GET_FC_FTYPE(fctl) ) {
case WLAN_FTYPE_MGMT:
hdrlen = WLAN_HDR_A3_LEN;
break;
case WLAN_FTYPE_DATA:
hdrlen = WLAN_HDR_A3_LEN;
if ( WLAN_GET_FC_TODS(fctl) && WLAN_GET_FC_FROMDS(fctl) ) {
hdrlen += WLAN_ADDR_LEN;
}
break;
case WLAN_FTYPE_CTL:
hdrlen = WLAN_CTL_FRAMELEN(WLAN_GET_FC_FSTYPE(fctl)) -
WLAN_FCS_LEN;
break;
default:
hdrlen = WLAN_HDR_A3_LEN;
}
return hdrlen;
}
#endif /* _P80211HDR_H */

View File

@ -253,8 +253,16 @@ typedef struct wlandevice
#endif
#ifdef WIRELESS_EXT
struct iw_statistics wstats;
struct iw_statistics wstats;
/* jkriegl: iwspy fields */
UINT8 spy_number;
char spy_address[IW_MAX_SPY][ETH_ALEN];
struct iw_quality spy_stat[IW_MAX_SPY];
#endif
} wlandevice_t;
/* WEP stuff */

View File

@ -49,8 +49,6 @@
*
* --------------------------------------------------------------------
*/
/*================================================================*/
/* System Includes */
@ -257,6 +255,26 @@ int skb_ether_to_p80211( wlandevice_t *wlandev, UINT32 ethconv, struct sk_buff *
return 0;
}
/* jkriegl: from orinoco, modified */
void orinoco_spy_gather(wlandevice_t *wlandev, char *mac, p80211_rxmeta_t *rxmeta)
{
int i;
/* Gather wireless spy statistics: for each packet, compare the
* source address with out list, and if match, get the stats... */
for (i = 0; i < wlandev->spy_number; i++) {
if (!memcmp(wlandev->spy_address[i], mac, ETH_ALEN)) {
memcpy(wlandev->spy_address[i], mac, ETH_ALEN);
wlandev->spy_stat[i].level = rxmeta->signal - 0x95;
wlandev->spy_stat[i].noise = rxmeta->noise - 0x95;
wlandev->spy_stat[i].qual = (rxmeta->signal > rxmeta->noise) ? \
(rxmeta->signal - rxmeta->noise) : 0;
wlandev->spy_stat[i].updated = 0x7;
}
}
}
/*----------------------------------------------------------------
* p80211pb_80211_to_ether
@ -478,6 +496,14 @@ int skb_p80211_to_ether( wlandevice_t *wlandev, UINT32 ethconv, struct sk_buff *
skb->protocol = eth_type_trans(skb, netdev);
skb->mac.raw = (unsigned char *) e_hdr; /* new MAC header */
/* jkriegl: process signal and noise as set in hfa384x_int_rx() */
/* jkriegl: only process signal/noise if requested by iwspy */
if (wlandev->spy_number)
orinoco_spy_gather(wlandev, skb->mac.ethernet->h_source, P80211SKB_RXMETA(skb));
/* Free the metadata */
p80211skb_rxmeta_detach(skb);
DBFEXIT;
return 0;
}
@ -513,27 +539,141 @@ int p80211_stt_findproto(UINT16 proto)
return 0;
}
#if 0
/* MSM: This function is currently unused. Not sure if we'll ever need it. */
/*----------------------------------------------------------------
* p80211_stt_addproto
* p80211skb_rxmeta_detach
*
* Add a protocol to the 802.1h Selective Translation Table.
* Disconnects the frmmeta and rxmeta from an skb.
*
* Arguments:
* proto protocl number (in host order) to search for.
* wlandev The wlandev this skb belongs to.
* skb The skb we're attaching to.
*
* Returns:
* nothing
* 0 on success, non-zero otherwise
*
* Call context:
* May be called in interrupt or non-interrupt context
----------------------------------------------------------------*/
int p80211_stt_addproto(UINT16 proto)
void
p80211skb_rxmeta_detach(struct sk_buff *skb)
{
p80211_rxmeta_t *rxmeta;
p80211_frmmeta_t *frmmeta;
DBFENTER;
/* Sanity checks */
if ( skb==NULL ) { /* bad skb */
WLAN_LOG_DEBUG(1, "Called w/ null skb.\n");
goto exit;
}
frmmeta = P80211SKB_FRMMETA(skb);
if ( frmmeta == NULL ) { /* no magic */
WLAN_LOG_DEBUG(1, "Called w/ bad frmmeta magic.\n");
goto exit;
}
rxmeta = frmmeta->rx;
if ( rxmeta == NULL ) { /* bad meta ptr */
WLAN_LOG_DEBUG(1, "Called w/ bad rxmeta ptr.\n");
goto exit;
}
/* Free rxmeta */
kfree(rxmeta);
/* Clear skb->cb */
memset(skb->cb, 0, sizeof(skb->cb));
exit:
DBFEXIT;
return;
}
#endif
/*----------------------------------------------------------------
* p80211skb_rxmeta_attach
*
* Allocates a p80211rxmeta structure, initializes it, and attaches
* it to an skb.
*
* Arguments:
* wlandev The wlandev this skb belongs to.
* skb The skb we're attaching to.
*
* Returns:
* 0 on success, non-zero otherwise
*
* Call context:
* May be called in interrupt or non-interrupt context
----------------------------------------------------------------*/
int
p80211skb_rxmeta_attach(struct wlandevice *wlandev, struct sk_buff *skb)
{
int result = 0;
p80211_rxmeta_t *rxmeta;
p80211_frmmeta_t *frmmeta;
DBFENTER;
/* If these already have metadata, we error out! */
if (P80211SKB_RXMETA(skb) != NULL) {
WLAN_LOG_ERROR("%s: RXmeta already attached!\n",
wlandev->name);
result = 0;
goto exit;
}
/* Allocate the rxmeta */
rxmeta = kmalloc(sizeof(p80211_rxmeta_t), GFP_ATOMIC);
if ( rxmeta == NULL ) {
WLAN_LOG_ERROR("%s: Failed to allocate rxmeta.\n",
wlandev->name);
result = 1;
goto exit;
}
/* Initialize the rxmeta */
memset(rxmeta, 0, sizeof(p80211_rxmeta_t));
rxmeta->wlandev = wlandev;
rxmeta->hosttime = jiffies;
/* Overlay a frmmeta_t onto skb->cb */
memset(skb->cb, 0, sizeof(p80211_frmmeta_t));
frmmeta = (p80211_frmmeta_t*)(skb->cb);
frmmeta->magic = P80211_FRMMETA_MAGIC;
frmmeta->rx = rxmeta;
exit:
DBFEXIT;
return result;
}
/*----------------------------------------------------------------
* p80211skb_free
*
* Frees an entire p80211skb by checking and freeing the meta struct
* and then freeing the skb.
*
* Arguments:
* wlandev The wlandev this skb belongs to.
* skb The skb we're attaching to.
*
* Returns:
* 0 on success, non-zero otherwise
*
* Call context:
* May be called in interrupt or non-interrupt context
----------------------------------------------------------------*/
void
p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb)
{
p80211_frmmeta_t *meta;
DBFENTER;
meta = P80211SKB_FRMMETA(skb);
if ( meta && meta->rx) {
p80211skb_rxmeta_detach(skb);
} else {
WLAN_LOG_ERROR("Freeing an skb (%p) w/ no frmmeta.\n", skb);
}
dev_kfree_skb(skb);
DBFEXIT;
return;
}

View File

@ -216,3 +216,6 @@ EXPORT_SYMBOL(wlan_setup);
EXPORT_SYMBOL(wlan_unsetup);
EXPORT_SYMBOL(p80211_suspend);
EXPORT_SYMBOL(p80211_resume);
EXPORT_SYMBOL(p80211skb_free);
EXPORT_SYMBOL(p80211skb_rxmeta_attach);

View File

@ -763,6 +763,7 @@ int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd)
}
bail:
DBFEXIT;
return result; /* If allocate,copyfrom or copyto fails, return errno */
}

View File

@ -1145,6 +1145,51 @@ static int p80211wext_siwretry(netdevice_t *dev,
#endif /* WIRELESS_EXT > 10 */
#if WIRELESS_EXT > 9
static int p80211wext_siwtxpow(netdevice_t *dev,
struct iw_request_info *info,
struct iw_param *rrq, char *extra)
{
wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
p80211item_uint32_t mibitem;
p80211msg_dot11req_mibset_t msg;
int result;
int err = 0;
DBFENTER;
if (!wlan_wext_write) {
err = (-EOPNOTSUPP);
goto exit;
}
msg.msgcode = DIDmsg_dot11req_mibset;
switch (rrq->value) {
case 1 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel1; break;
case 2 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel2; break;
case 3 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel3; break;
case 4 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel4; break;
case 5 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel5; break;
case 6 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel6; break;
case 7 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel7; break;
case 8 : mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel8; break;
default: mibitem.did = DIDmib_dot11phy_dot11PhyTxPowerTable_dot11TxPowerLevel8; break;
}
memcpy(&msg.mibattribute.data, &mibitem, sizeof(mibitem));
result = p80211req_dorequest(wlandev, (UINT8*)&msg);
if (result) {
err = -EFAULT;
goto exit;
}
exit:
DBFEXIT;
return err;
}
static int p80211wext_giwtxpow(netdevice_t *dev,
struct iw_request_info *info,
struct iw_param *rrq, char *extra)
@ -1183,6 +1228,80 @@ static int p80211wext_giwtxpow(netdevice_t *dev,
}
#endif /* WIRELESS_EXT > 9 */
static int p80211wext_siwspy(netdevice_t *dev,
struct iw_request_info *info,
struct iw_point *srq, char *extra)
{
wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
struct sockaddr address[IW_MAX_SPY];
int number = srq->length;
int i;
DBFENTER;
/* Copy the data from the input buffer */
memcpy(address, extra, sizeof(struct sockaddr)*number);
wlandev->spy_number = 0;
if (number > 0) {
/* extract the addresses */
for (i = 0; i < number; i++) {
memcpy(wlandev->spy_address[i], address[i].sa_data, ETH_ALEN);
}
/* reset stats */
memset(wlandev->spy_stat, 0, sizeof(struct iw_quality) * IW_MAX_SPY);
/* set number of addresses */
wlandev->spy_number = number;
}
DBFEXIT;
return 0;
}
/* jkriegl: from orinoco, modified */
static int p80211wext_giwspy(netdevice_t *dev,
struct iw_request_info *info,
struct iw_point *srq, char *extra)
{
wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
struct sockaddr address[IW_MAX_SPY];
struct iw_quality spy_stat[IW_MAX_SPY];
int number;
int i;
DBFENTER;
number = wlandev->spy_number;
if (number > 0) {
/* populate address and spy struct's */
for (i = 0; i < number; i++) {
memcpy(address[i].sa_data, wlandev->spy_address[i], ETH_ALEN);
address[i].sa_family = AF_UNIX;
memcpy(&spy_stat[i], &wlandev->spy_stat[i], sizeof(struct iw_quality));
}
/* reset update flag */
for (i=0; i < number; i++)
wlandev->spy_stat[i].updated = 0;
}
/* push stuff to user space */
srq->length = number;
memcpy(extra, address, sizeof(struct sockaddr)*number);
memcpy(extra+sizeof(struct sockaddr)*number, spy_stat, sizeof(struct iw_quality)*number);
DBFEXIT;
return 0;
}
/*
typedef int (*iw_handler)(netdevice_t *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra);
@ -1206,8 +1325,8 @@ static iw_handler p80211wext_handlers[] = {
(iw_handler) NULL, /* kernel code */ /* SIOCGIWPRIV */
(iw_handler) NULL, /* not used */ /* SIOCSIWSTATS */
(iw_handler) NULL, /* kernel code */ /* SIOCGIWSTATS */
(iw_handler) NULL, /* SIOCSIWSPY */
(iw_handler) NULL, /* SIOCGIWSPY */
(iw_handler) p80211wext_siwspy, /* SIOCSIWSPY */
(iw_handler) p80211wext_giwspy, /* SIOCGIWSPY */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* SIOCSIWAP */
@ -1233,7 +1352,7 @@ static iw_handler p80211wext_handlers[] = {
(iw_handler) p80211wext_giwrts, /* SIOCGIWRTS */
(iw_handler) p80211wext_siwfrag, /* SIOCSIWFRAG */
(iw_handler) p80211wext_giwfrag, /* SIOCGIWFRAG */
(iw_handler) NULL, /* SIOCSIWTXPOW */
(iw_handler) NULL, /* SIOCSIWTXPOW */
(iw_handler) p80211wext_giwtxpow, /* SIOCGIWTXPOW */
(iw_handler) p80211wext_siwretry, /* SIOCSIWRETRY */
(iw_handler) p80211wext_giwretry, /* SIOCGIWRETRY */

View File

@ -115,6 +115,7 @@
*/
/*================================================================*/
/* System Includes */
#define WLAN_DBVAR prism2_debug
#include <wlan/version.h>
@ -3583,7 +3584,6 @@ failed:
return;
}
/*----------------------------------------------------------------
* hfa384x_int_rx
*
@ -3608,6 +3608,7 @@ void hfa384x_int_rx(wlandevice_t *wlandev)
int result;
int hdrlen;
UINT16 fc;
p80211_rxmeta_t *rxmeta;
struct sk_buff *skb = NULL;
UINT8 *datap;
@ -3646,6 +3647,7 @@ void hfa384x_int_rx(wlandevice_t *wlandev)
switch( HFA384x_RXSTATUS_MACPORT_GET(rxdesc.status) )
{
case 0:
fc = ieee2host16(rxdesc.frame_control);
/* If exclude and we receive an unencrypted, drop it */
@ -3654,11 +3656,7 @@ void hfa384x_int_rx(wlandevice_t *wlandev)
goto done;
}
if ( WLAN_GET_FC_TODS(fc) && WLAN_GET_FC_FROMDS(fc) ) {
hdrlen = WLAN_HDR_A4_LEN;
} else {
hdrlen = WLAN_HDR_A3_LEN;
}
hdrlen = p80211_headerlen(fc);
/* Allocate the buffer, note CRC (aka FCS). pballoc */
/* assumes there needs to be space for one */
@ -3709,16 +3707,27 @@ void hfa384x_int_rx(wlandevice_t *wlandev)
memset (datap, 0xff, WLAN_CRC_LEN);
skb->mac.raw = skb->data;
/* Attach the rxmeta, set some stuff */
p80211skb_rxmeta_attach(wlandev, skb);
rxmeta = P80211SKB_RXMETA(skb);
rxmeta->mactime = rxdesc.time;
rxmeta->rxrate = rxdesc.rate;
rxmeta->signal = rxdesc.signal;
rxmeta->noise = rxdesc.silence;
prism2sta_ev_rx(wlandev, skb);
goto done;
case 7:
if ( ! HFA384x_RXSTATUS_ISFCSERR(rxdesc.status) ) {
hfa384x_int_rxmonitor( wlandev, rxfid, &rxdesc);
} else {
WLAN_LOG_DEBUG(3,"Received monitor frame: FCSerr set\n");
}
goto done;
default:
WLAN_LOG_WARNING("Received frame on unsupported port=%d\n",
HFA384x_RXSTATUS_MACPORT_GET(rxdesc.status) );
goto done;
@ -3770,46 +3779,8 @@ void hfa384x_int_rxmonitor( wlandevice_t *wlandev, UINT16 rxfid, hfa384x_rx_fram
/* Don't forget the status, time, and data_len fields are in host order */
/* Figure out how big the frame is */
fc = ieee2host16(rxdesc->frame_control);
switch ( WLAN_GET_FC_FTYPE(fc) )
{
case WLAN_FTYPE_DATA:
if ( WLAN_GET_FC_TODS(fc) && WLAN_GET_FC_FROMDS(fc) ) {
hdrlen = WLAN_HDR_A4_LEN;
} else {
hdrlen = WLAN_HDR_A3_LEN;
}
datalen = hfa384x2host_16(rxdesc->data_len);
break;
case WLAN_FTYPE_MGMT:
hdrlen = WLAN_HDR_A3_LEN;
datalen = hfa384x2host_16(rxdesc->data_len);
break;
case WLAN_FTYPE_CTL:
switch ( WLAN_GET_FC_FSTYPE(fc) )
{
case WLAN_FSTYPE_PSPOLL:
case WLAN_FSTYPE_RTS:
case WLAN_FSTYPE_CFEND:
case WLAN_FSTYPE_CFENDCFACK:
hdrlen = 16;
break;
case WLAN_FSTYPE_CTS:
case WLAN_FSTYPE_ACK:
hdrlen = 10;
break;
default:
hdrlen = WLAN_HDR_A3_LEN;
break;
}
datalen = 0;
break;
default:
hdrlen = WLAN_HDR_A3_LEN;
datalen = hfa384x2host_16(rxdesc->data_len);
WLAN_LOG_DEBUG(1, "unknown frm: fc=0x%04x\n", fc);
break;
}
hdrlen = p80211_headerlen(fc);
datalen = hfa384x2host_16(rxdesc->data_len);
/* Allocate an ind message+framesize skb */
skblen = sizeof(p80211msg_lnxind_wlansniffrm_t) +

View File

@ -4081,6 +4081,7 @@ void hfa384x_usbin_rx(wlandevice_t *wlandev, hfa384x_usbin_t *usbin)
p80211_hdr_t *w_hdr;
struct sk_buff *skb = NULL;
int hdrlen;
p80211_rxmeta_t *rxmeta;
UINT16 fc;
UINT8 *datap;
@ -4105,11 +4106,7 @@ void hfa384x_usbin_rx(wlandevice_t *wlandev, hfa384x_usbin_t *usbin)
goto done;
}
if ( WLAN_GET_FC_TODS(fc) && WLAN_GET_FC_FROMDS(fc) ) {
hdrlen = WLAN_HDR_A4_LEN;
} else {
hdrlen = WLAN_HDR_A3_LEN;
}
hdrlen = p80211_headerlen(fc);
/* Allocate the buffer, note CRC (aka FCS). pballoc */
/* assumes there needs to be space for one */
@ -4152,6 +4149,14 @@ void hfa384x_usbin_rx(wlandevice_t *wlandev, hfa384x_usbin_t *usbin)
memset (datap, 0xff, WLAN_CRC_LEN);
skb->mac.raw = skb->data;
/* Attach the rxmeta, set some stuff */
p80211skb_rxmeta_attach(wlandev, skb);
rxmeta = P80211SKB_RXMETA(skb);
rxmeta->mactime = usbin->rxfrm.desc.time;
rxmeta->rxrate = usbin->rxfrm.desc.rate;
rxmeta->signal = usbin->rxfrm.desc.signal;
rxmeta->noise = usbin->rxfrm.desc.silence;
prism2sta_ev_rx(wlandev, skb);
break;
@ -4215,46 +4220,8 @@ static void hfa384x_int_rxmonitor( wlandevice_t *wlandev, hfa384x_usb_rxfrm_t *r
/* Don't forget the status, time, and data_len fields are in host order */
/* Figure out how big the frame is */
fc = ieee2host16(rxdesc->frame_control);
switch ( WLAN_GET_FC_FTYPE(fc) )
{
case WLAN_FTYPE_DATA:
if ( WLAN_GET_FC_TODS(fc) && WLAN_GET_FC_FROMDS(fc) ) {
hdrlen = WLAN_HDR_A4_LEN;
} else {
hdrlen = WLAN_HDR_A3_LEN;
}
datalen = hfa384x2host_16(rxdesc->data_len);
break;
case WLAN_FTYPE_MGMT:
hdrlen = WLAN_HDR_A3_LEN;
datalen = hfa384x2host_16(rxdesc->data_len);
break;
case WLAN_FTYPE_CTL:
switch ( WLAN_GET_FC_FSTYPE(fc) )
{
case WLAN_FSTYPE_PSPOLL:
case WLAN_FSTYPE_RTS:
case WLAN_FSTYPE_CFEND:
case WLAN_FSTYPE_CFENDCFACK:
hdrlen = 16;
break;
case WLAN_FSTYPE_CTS:
case WLAN_FSTYPE_ACK:
hdrlen = 10;
break;
default:
hdrlen = WLAN_HDR_A3_LEN;
break;
}
datalen = 0;
break;
default:
hdrlen = WLAN_HDR_A3_LEN;
datalen = hfa384x2host_16(rxdesc->data_len);
WLAN_LOG_DEBUG(1, "unknown frm: fc=0x%04x\n", fc);
break;
}
hdrlen = p80211_headerlen(fc);
datalen = hfa384x2host_16(rxdesc->data_len);
/* Allocate an ind message+framesize skb */
skblen = sizeof(p80211msg_lnxind_wlansniffrm_t) +