diff -r -u3 linux-wlan-ng-0.1.8-pre13/src/prism2/driver/Makefile wlan-monitor/src/prism2/driver/Makefile --- linux-wlan-ng-0.1.8-pre13/src/prism2/driver/Makefile Thu Apr 5 13:38:48 2001 +++ wlan-monitor/src/prism2/driver/Makefile Sun Jul 8 03:43:07 2001 @@ -147,6 +147,7 @@ -I$(LINUX_SRC)/include \ $(WLAN_INCLUDE_DEBUG) endif +CPPFLAGS += -DMONITOR # Dependency Source List DEP_SRC=$(SRC) diff -r -u3 linux-wlan-ng-0.1.8-pre13/src/prism2/driver/hfa384x.c wlan-monitor/src/prism2/driver/hfa384x.c --- linux-wlan-ng-0.1.8-pre13/src/prism2/driver/hfa384x.c Fri May 4 15:37:34 2001 +++ wlan-monitor/src/prism2/driver/hfa384x.c Sun Jul 8 03:52:58 2001 @@ -1378,6 +1378,50 @@ return result; } +#ifdef MONITOR +/*---------------------------------------------------------------- +* hfa384x_cmd_monitor +* +* Enables the 'monitor mode' of the MAC. Here's the description of +* monitor mode that I've received thus far: +* +* "The "monitor mode" of operation is that the MAC passes all +* frames for which the PLCP checks are correct. All received +* MPDUs are passed to the host with MAC Port = 7, with a +* receive status of good, FCS error, or undecryptable. Passing +* certain MPDUs is a violation of the 802.11 standard, but useful +* for a debugging tool." Normal communication is not possible +* while monitor mode is enabled. +* +* Arguments: +* hw device structure +* enable a code (0x0b|0x0f) that enables/disables +* monitor mode. (host order) +* +* Returns: +* 0 success +* >0 f/w reported failure - f/w status code +* <0 driver reported error (timeout|bad arg) +* +* Side effects: +* +* Call context: +* process thread +----------------------------------------------------------------*/ +int hfa384x_cmd_monitor(hfa384x_t *hw, UINT16 enable) +{ + int result = 0; + UINT16 cmd; + DBFENTER; + cmd = HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_MONITOR) | + HFA384x_CMD_AINFO_SET(enable); + result = hfa384x_docmd_wait(hw, cmd, 0, 0, 0); + + DBFEXIT; + return result; +} +#endif + /*---------------------------------------------------------------- * hfa384x_cmd_download diff -r -u3 linux-wlan-ng-0.1.8-pre13/src/prism2/driver/prism2mgmt.c wlan-monitor/src/prism2/driver/prism2mgmt.c --- linux-wlan-ng-0.1.8-pre13/src/prism2/driver/prism2mgmt.c Thu May 3 10:00:17 2001 +++ wlan-monitor/src/prism2/driver/prism2mgmt.c Sun Jul 8 03:50:15 2001 @@ -1987,3 +1987,201 @@ return result; } + +#ifdef MONITOR +/*---------------------------------------------------------------- +* prism2mgmt_wlansniff +* +* Start or stop sniffing. +* +* Arguments: +* wlandev wlan device structure +* msgp ptr to msg buffer +* +* Returns: +* 0 success and done +* <0 success, but we're waiting for something to finish. +* >0 an error occurred while handling the message. +* Side effects: +* +* Call context: +* process thread (usually) +* interrupt +----------------------------------------------------------------*/ +int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) +{ + prism2sta_priv_t *priv = (prism2sta_priv_t*)wlandev->priv; + hfa384x_t *hw = priv->hw; + int result = 0; + p80211msg_lnxreq_wlansniff_t *msg = msgp; + UINT16 word; + + DBFENTER; + + msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; + + switch (msg->enable.data) + { + case P80211ENUM_truth_false: + /* Confirm that we're in monitor mode */ + if ( !priv->sniffing ) { + msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters; + result = 0; + } + /* Disable monitor mode */ + result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_DISABLE); + if ( result ) { + WLAN_LOG_DEBUG1(1, + "failed to disable monitor mode, result=%d\n", + result); + goto failed; + } + /* Disable port 0 */ + result = hfa384x_cmd_disable(hw, 0); + if ( result ) { + WLAN_LOG_DEBUG1(1, + "failed to disable port 0 after sniffing, result=%d\n", + result); + goto failed; + } + /* Clear the driver state */ + priv->sniffing = 0; + + /* Restore the wepflags */ + result = hfa384x_drvr_setconfig16(hw, + HFA384x_RID_CNFWEPFLAGS, + &(priv->presniff_wepflags)); + if ( result ) { + WLAN_LOG_DEBUG2(1, + "failed to restore wepflags=0x%04x, result=%d\n", + word, + result); + goto failed; + } + /* Set the port to its prior type and enable (if necessary) */ + if (priv->presniff_port_type != 0 ) { + word = priv->presniff_port_type; + result = hfa384x_drvr_setconfig16(hw, + HFA384x_RID_CNFPORTTYPE, &word); + if ( result ) { + WLAN_LOG_DEBUG1(1, + "failed to restore porttype, result=%d\n", + result); + goto failed; + } + /* Enable the port */ + result = hfa384x_cmd_enable(hw, 0); + if ( result ) { + WLAN_LOG_DEBUG1(1, + "failed to enable port to presniff setting, result=%d\n", + result); + goto failed; + } + } + + msg->resultcode.data = P80211ENUM_resultcode_success; + result = 0; + goto exit; + break; + case P80211ENUM_truth_true: + /* Disable the port (if enabled), only check Port 0 */ + if ( hw->port_enabled[0] ) { + /* Save macport 0 state */ + result = hfa384x_drvr_getconfig16(hw, + HFA384x_RID_CNFPORTTYPE, + &(priv->presniff_port_type)); + if ( result ) { + WLAN_LOG_DEBUG1(1,"failed to read porttype, result=%d\n", result); + goto failed; + } + /* Save the wepflags state */ + result = hfa384x_drvr_getconfig16(hw, + HFA384x_RID_CNFWEPFLAGS, + &(priv->presniff_wepflags)); + if ( result ) { + WLAN_LOG_DEBUG1(1,"failed to read wepflags, result=%d\n", result); + goto failed; + } + result = hfa384x_cmd_disable(hw, 0); + if ( result ) { + WLAN_LOG_DEBUG1(1, + "failed to clear port 0 for sniffing, result=%d\n", + result); + goto failed; + } + } + else { + priv->presniff_port_type = 0; + } + /* Set the channel we wish to sniff */ + word = msg->channel.data; + result = hfa384x_drvr_setconfig16(hw, + HFA384x_RID_CNFOWNCHANNEL, &word); + if ( result ) { + WLAN_LOG_DEBUG2(1, + "failed to set channel %d, result=%d\n", + word, + result); + goto failed; + } + /* Set the port type to pIbss */ + word = HFA384x_PORTTYPE_IBSS; + result = hfa384x_drvr_setconfig16(hw, + HFA384x_RID_CNFPORTTYPE, &word); + if ( result ) { + WLAN_LOG_DEBUG2(1, + "failed to set porttype %d, result=%d\n", + word, + result); + goto failed; + } + /* Set the wepflags for no decryption */ + word = HFA384x_WEPFLAGS_DISABLE_TXCRYPT | + HFA384x_WEPFLAGS_DISABLE_RXCRYPT; + result = hfa384x_drvr_setconfig16(hw, + HFA384x_RID_CNFWEPFLAGS, &word); + if ( result ) { + WLAN_LOG_DEBUG2(1, + "failed to set wepflags=0x%04x, result=%d\n", + word, + result); + goto failed; + } + /* Enable the port */ + result = hfa384x_cmd_enable(hw, 0); + if ( result ) { + WLAN_LOG_DEBUG1(1, + "failed to enable port for sniffing, result=%d\n", + result); + goto failed; + } + /* Enable monitor mode */ + result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_ENABLE); + if ( result ) { + WLAN_LOG_DEBUG1(1, + "failed to enable monitor mode, result=%d\n", + result); + goto failed; + } + /* Set the driver state */ + priv->sniffing = 1; + + msg->resultcode.data = P80211ENUM_resultcode_success; + result = 0; + goto exit; + break; + default: + msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters; + result = 0; + goto exit; + break; + } + +failed: + msg->resultcode.data = P80211ENUM_resultcode_refused; + result = 0; +exit: + DBFEXIT; + return result; +} +#endif diff -r -u3 linux-wlan-ng-0.1.8-pre13/src/prism2/driver/prism2sta.c wlan-monitor/src/prism2/driver/prism2sta.c --- linux-wlan-ng-0.1.8-pre13/src/prism2/driver/prism2sta.c Thu Apr 5 13:38:48 2001 +++ wlan-monitor/src/prism2/driver/prism2sta.c Sun Jul 8 04:31:34 2001 @@ -229,6 +229,9 @@ static void prism2sta_int_tx(wlandevice_t *wlandev); static void prism2sta_int_rx(wlandevice_t *wlandev); static int prism2sta_int_rx_typedrop( wlandevice_t *wlandev, UINT16 fc); +#ifdef MONITOR +static void prism2sta_int_rxmonitor( wlandevice_t *wlandev, UINT16 rxfid, hfa384x_rx_frame_t *rxdesc); +#endif static void prism2sta_int_alloc(wlandevice_t *wlandev); static void prism2sta_inf_handover( @@ -800,6 +803,12 @@ WLAN_LOG_DEBUG0(2,"Received mlme start request\n"); result = prism2mgmt_start(wlandev, msg); break; +#ifdef MONITOR + case DIDmsg_lnxreq_wlansniff : + WLAN_LOG_DEBUG0(2,"Received mlme wlansniff request\n"); + result = prism2mgmt_wlansniff(wlandev, msg); + break; +#endif case DIDmsg_p2req_readpda : WLAN_LOG_DEBUG0(2,"Received mlme readpda request\n"); result = prism2mgmt_readpda(wlandev, msg); @@ -2344,6 +2353,17 @@ /* Call p80211netdev_rx - it will NOT free pb */ p80211netdev_rx(wlandev, pb); break; +#ifdef MONITOR + case 7: + if ( ! HFA384x_RXSTATUS_ISFCSERR(rxdesc.status) ) { + /* Copy to wlansnif skb */ + prism2sta_int_rxmonitor( wlandev, rxfid, &rxdesc); + } else { + WLAN_LOG_DEBUG0(3,"Received monitor frame: FCSerr set\n" +); + } + break; +#endif default: WLAN_LOG_WARNING1("Received frame on unsupported port=%d\n", HFA384x_RXSTATUS_MACPORT_GET(rxdesc.status) ); @@ -2358,6 +2378,179 @@ DBFEXIT; return; } + + +#ifdef MONITOR +/*---------------------------------------------------------------- +* prism2sta_int_rxmonitor +* +* Helper function for int_rx. Handles monitor frames. +* Note that this function allocates space for the FCS and sets it +* to 0xffffffff. The hfa384x doesn't give us the FCS value but the +* higher layers expect it. 0xffffffff is used as a flag to indicate +* the FCS is bogus. +* +* Arguments: +* wlandev wlan device structure +* rxfid received FID +* rxdesc rx descriptor read from card in int_rx +* +* Returns: +* nothing +* +* Side effects: +* Allocates an skb and passes it up via p80211ind_sniff() +* Call context: +* interrupt +----------------------------------------------------------------*/ +void prism2sta_int_rxmonitor( wlandevice_t *wlandev, UINT16 rxfid, hfa384x_rx_frame_t *rxdesc) +{ + prism2sta_priv_t *priv = wlandev->priv; + hfa384x_t *hw = priv->hw; + UINT hdrlen = 0; + UINT datalen = 0; + UINT skblen = 0; + p80211msg_lnxind_wlansniffrm_t *msg; + UINT8 *datap; + UINT16 fc; + struct sk_buff *skb; + + DBFENTER; + /* 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 = rxdesc->data_len; + break; + case WLAN_FTYPE_MGMT: + hdrlen = WLAN_HDR_A3_LEN; + datalen = 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; + } + datalen = 0; + break; + default: + WLAN_LOG_DEBUG1(1, "unknown frm: fc=0x%04x\n", fc); + return; + } + + /* Allocate an ind message+framesize skb */ + skblen = sizeof(p80211msg_lnxind_wlansniffrm_t) + + hdrlen + datalen + WLAN_CRC_LEN; + /* sanity check the length */ + if ( skblen > + (sizeof(p80211msg_lnxind_wlansniffrm_t) + + WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN) ) { + WLAN_LOG_DEBUG1(1, "overlen frm: len=%d\n", + skblen - sizeof(p80211msg_lnxind_wlansniffrm_t)); + } + + if ( (skb = alloc_skb(skblen, GFP_ATOMIC)) == NULL ) { + WLAN_LOG_DEBUG1(2, + "alloc_skb failed trying to allocate %d bytes\n", skblen); + return; + } + skb_put(skb, skblen); + datap = skb->data + sizeof(p80211msg_lnxind_wlansniffrm_t); + msg = (p80211msg_lnxind_wlansniffrm_t*)skb->data; + + /* Initialize the message members */ + msg->msgcode = DIDmsg_lnxind_wlansniffrm; + msg->msglen = sizeof(p80211msg_lnxind_wlansniffrm_t); + strcpy(msg->devname, wlandev->name); + + msg->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime; + msg->hosttime.status = 0; + msg->hosttime.len = 4; + msg->hosttime.data = jiffies; + + msg->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime; + msg->mactime.status = 0; + msg->mactime.len = 4; + msg->mactime.data = rxdesc->time; + + msg->channel.did = DIDmsg_lnxind_wlansniffrm_channel; + msg->channel.status = P80211ENUM_msgitem_status_no_value; + msg->channel.len = 4; + msg->channel.data = 0; + + msg->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi; + msg->rssi.status = P80211ENUM_msgitem_status_no_value; + msg->rssi.len = 4; + msg->rssi.data = 0; + + msg->sq.did = DIDmsg_lnxind_wlansniffrm_sq; + msg->sq.status = P80211ENUM_msgitem_status_no_value; + msg->sq.len = 4; + msg->sq.data = 0; + + msg->signal.did = DIDmsg_lnxind_wlansniffrm_signal; + msg->signal.status = 0; + msg->signal.len = 4; + msg->signal.data = rxdesc->signal; + + msg->noise.did = DIDmsg_lnxind_wlansniffrm_noise; + msg->noise.status = 0; + msg->noise.len = 4; + msg->noise.data = rxdesc->silence; + + msg->rate.did = DIDmsg_lnxind_wlansniffrm_rate; + msg->rate.status = 0; + msg->rate.len = 4; + msg->rate.data = rxdesc->rate / 5; /* set to 802.11 units */ + + msg->istx.did = DIDmsg_lnxind_wlansniffrm_istx; + msg->istx.status = 0; + msg->istx.len = 4; + msg->istx.data = P80211ENUM_truth_false; + + msg->frmlen.did = DIDmsg_lnxind_wlansniffrm_frmlen; + msg->frmlen.status = 0; + msg->frmlen.len = 4; + msg->frmlen.data = hdrlen + datalen + WLAN_CRC_LEN; + + /* Copy the 802.11 header to the skb (ctl frames may be less than a full header) */ + memcpy( datap, &(rxdesc->frame_control), hdrlen); + + /* If any, copy the data from the card to the skb */ + if ( datalen > 0 ) + { + hfa384x_copy_from_bap(hw, + hw->bap, rxfid, HFA384x_RX_DATA_OFF, + datap + hdrlen, datalen); + } + + /* Set the CRC */ + memset( ((UINT8 *)(skb->data)) + skb->len - WLAN_CRC_LEN, 0xff, WLAN_CRC_LEN); + + /* Pass it up */ + p80211ind_sniff(wlandev, skb); + + DBFEXIT; + return; +} +#endif + /*---------------------------------------------------------------- diff -r -u3 linux-wlan-ng-0.1.8-pre13/src/prism2/include/prism2/hfa384x.h wlan-monitor/src/prism2/include/prism2/hfa384x.h --- linux-wlan-ng-0.1.8-pre13/src/prism2/include/prism2/hfa384x.h Fri May 4 15:37:34 2001 +++ wlan-monitor/src/prism2/include/prism2/hfa384x.h Sun Jul 8 03:53:45 2001 @@ -1953,6 +1953,9 @@ int hfa384x_cmd_notify(hfa384x_t *hw, UINT16 reclaim, UINT16 fid); int hfa384x_cmd_inquiry(hfa384x_t *hw, UINT16 fid); int hfa384x_cmd_access(hfa384x_t *hw, UINT16 write, UINT16 rid); +#ifdef MONITOR +int hfa384x_cmd_monitor(hfa384x_t *hw, UINT16 enable); +#endif int hfa384x_cmd_download(hfa384x_t *hw, UINT16 mode, UINT16 lowaddr, UINT16 highaddr, UINT16 codelen); int hfa384x_cmd_aux_enable(hfa384x_t *hw); diff -r -u3 linux-wlan-ng-0.1.8-pre13/src/prism2/include/prism2/prism2mgmt.h wlan-monitor/src/prism2/include/prism2/prism2mgmt.h --- linux-wlan-ng-0.1.8-pre13/src/prism2/include/prism2/prism2mgmt.h Thu Apr 5 13:38:48 2001 +++ wlan-monitor/src/prism2/include/prism2/prism2mgmt.h Sun Jul 8 04:37:11 2001 @@ -60,6 +60,8 @@ #ifndef _PRISM2MGMT_H #define _PRISM2MGMT_H +#define MONITOR /* support monitoring. XXX move to a better place */ + /*=============================================================*/ /*------ Constants --------------------------------------------*/ @@ -181,6 +183,11 @@ } channel_info; /* State variables */ +#ifdef MONITOR + UINT sniffing; + UINT presniff_port_type; + UINT16 presniff_wepflags; +#endif UINT qos_enable; /* C bool */ UINT8 qos_dscpmap[P2_DSCP_MAX]; UINT priv_invoked; /* C bool */ @@ -223,6 +230,9 @@ int prism2mgmt_reassociate(wlandevice_t *wlandev, void *msgp); int prism2mgmt_disassociate(wlandevice_t *wlandev, void *msgp); int prism2mgmt_start(wlandevice_t *wlandev, void *msgp); +#ifdef MONITOR +int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp); +#endif int prism2mgmt_readpda(wlandevice_t *wlandev, void *msgp); int prism2mgmt_readcis(wlandevice_t *wlandev, void *msgp); int prism2mgmt_auxport_state(wlandevice_t *wlandev, void *msgp);