[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [ns] NAV bug in 802.11 MAC
Neeraj Poojary wrote:
>
> aman,
> i don't have a patch for the NAV problem. please let me know when you have
> one ready.
>
> you're right about the possible side-effects from creating an intermediate
> recv state. i should change my code.
>
> thanks,
> neeraj
I'm appending the modified files mac*802*.{cc, h}
There are a bunch of other changes to the files (from the original src
you might have) besides the above bug fix. Most of them have to do with
using the MAC within an infrastructure BSS. Feel free to ignore them;
I'm just too lazy to create a patch for just the above bug fix against
the original code; anyway all my modifications shouldn't screw up
anything
for you.
I'd greatly appreciate a code review w.r.t. the fix for the above bug;
I'm not sure if I was really thinking straight when I did this.. and
don't
have a good test case.
Aside: some of the calculations of transmission time were flawed w.r.t.
the
spec.. so I've attempted to fix them too.
:a
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1997 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the Computer Systems
* Engineering Group at Lawrence Berkeley Laboratory.
* 4. Neither the name of the University nor of the Laboratory may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* Ported from CMU/Monarch's code, nov'98 -Padma.*/
#include "delay.h"
#include "connector.h"
#include "packet.h"
#include "random.h"
// #define DEBUG
//#include <debug.h>
#include "arp.h"
#include "ll.h"
#include "mac.h"
#include "mac-timers.h"
#include "mac-802_11.h"
#include "cmu-trace.h"
#define CHECK_BACKOFF_TIMER() \
{ \
if (is_idle() && mhBackoff_.paused()) \
mhBackoff_.resume(difs_); \
if (!is_idle() && mhBackoff_.busy() && !mhBackoff_.paused()) \
mhBackoff_.pause(); \
}
#define TRANSMIT(p, t) \
{ \
tx_active_ = p->copy(); \
\
/* \
* If I'm transmitting without doing CS, such as when \
* sending an ACK, any incoming packet will be "missed" \
* and hence, must be discarded. \
*/ \
if (rx_state_ != MAC_IDLE) { \
struct hdr_mac802_11 *dh = HDR_MAC802_11(p); \
\
assert(dh->dh_fc.fc_type == MAC_Type_Control); \
assert(dh->dh_fc.fc_subtype == MAC_Subtype_ACK); \
\
assert(pktRx_); \
struct hdr_cmn *ch = HDR_CMN(pktRx_); \
\
ch->error() = 1; /* force packet discard */ \
} \
\
/* \
* pass the packet on the "interface" which will in turn \
* place the packet on the channel. \
* \
* NOTE: a handler is passed along so that the Network \
* Interface can distinguish between incoming and \
* outgoing packets. \
*/ \
downtarget_->recv(p->copy(), this); \
\
mhSend_.start(t); \
\
mhIF_.start(TX_Time(p)); \
}
#define SET_RX_STATE(x) \
{ \
rx_state_ = (x); \
\
CHECK_BACKOFF_TIMER(); \
}
#define SET_TX_STATE(x) \
{ \
tx_state_ = (x); \
\
CHECK_BACKOFF_TIMER(); \
}
/* ======================================================================
Global Variables
====================================================================== */
//extern char* pt_names[];
static PHY_MIB PMIB =
{
DSSS_CWMin, DSSS_CWMax, DSSS_SlotTime, DSSS_CCATime,
DSSS_RxTxTurnaroundTime, DSSS_SIFSTime, DSSS_PreambleLength,
DSSS_PLCPHeaderLength, DSSS_MinimumBandwidth
};
static MAC_MIB MMIB =
{
MAC_RTSThreshold, MAC_ShortRetryLimit,
MAC_LongRetryLimit, MAC_FragmentationThreshold,
MAC_MaxTransmitMSDULifetime, MAC_MaxReceiveLifetime,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* ======================================================================
TCL Hooks for the simulator
====================================================================== */
static class Mac802_11Class : public TclClass {
public:
Mac802_11Class() : TclClass("Mac/802_11") {}
TclObject* create(int, const char*const*) {
return (new Mac802_11(&PMIB, &MMIB));
}
} class_mac802_11;
/* ======================================================================
Mac Class Functions
====================================================================== */
Mac802_11::Mac802_11(PHY_MIB *p, MAC_MIB *m) : Mac(),
mhIF_(this), mhNav_(this), mhRecv_(this), mhSend_(this),
mhDefer_(this, p->SlotTime), mhBackoff_(this, p->SlotTime),
bss_id_(IBSS_ID)
{
macmib_ = m;
phymib_ = p;
nav_ = 0.0;
eifs_nav_ = 0.0;
tx_state_ = rx_state_ = MAC_IDLE;
tx_active_ = NULL;
pktRTS_ = 0;
pktCTRL_ = 0;
pktBeacon_ = 0;
cw_ = phymib_->CWMin;
ssrc_ = slrc_ = 0;
sifs_ = phymib_->SIFSTime;
pifs_ = sifs_ + phymib_->SlotTime;
difs_ = sifs_ + 2*phymib_->SlotTime;
eifs_ = sifs_ + difs_ + PLCP_Time + (8 * ETHER_ACK_LEN)/phymib_->MinimumBandwidth;
/* we accomplish defering for eifs_ following an error
* using a scheme based on setting the nav! the nav should
* be set to (eifs_ - difs_) really, since once the nav
* indicates the channel to be idle, we (in most practical
* situations I can think of..) we defer for difs_ anyway!
* so the below..
*/
eifs_ -= difs_;
tx_sifs_ = sifs_ - phymib_->RxTxTurnaroundTime;
tx_pifs_ = tx_sifs_ + phymib_->SlotTime;
tx_difs_ = tx_sifs_ + 2 * phymib_->SlotTime;
sta_seqno_ = 1;
cache_ = 0;
cache_node_count_ = 0;
}
int
Mac802_11::command(int argc, const char*const* argv)
{
if (argc == 3) {
if (strcmp(argv[1], "eot-target") == 0) {
EOTtarget_ = (NsObject*) TclObject::lookup(argv[2]);
if (EOTtarget_ == 0)
return TCL_ERROR;
return TCL_OK;
}
/* this is a gross hack! mac_mib is a static!!
* changing for one will change for all!!!!!!!
*/
if (strcmp(argv[1], "RTSThreshold") == 0) {
macmib_->RTSThreshold = atoi(argv[2]);
return TCL_OK;
}
if (strcmp(argv[1], "bss_id") == 0) {
bss_id_ = atoi(argv[2]);
return TCL_OK;
}
if (strcmp(argv[1], "nodes") == 0) {
if (cache_) return TCL_ERROR;
cache_node_count_ = atoi(argv[2]);
cache_ = new Host[cache_node_count_ + 1];
assert(cache_);
bzero(cache_, sizeof(Host) * (cache_node_count_+1 ));
return TCL_OK;
}
}
return Mac::command(argc, argv);
}
/* ======================================================================
Debugging Routines
====================================================================== */
void
Mac802_11::trace_pkt(Packet *p) {
struct hdr_cmn *ch = HDR_CMN(p);
struct hdr_mac802_11* dh = HDR_MAC802_11(p);
u_int16_t *t = (u_int16_t*) &dh->dh_fc;
fprintf(stderr, "\t[ %2x %2x %2x %2x ] %x %s %d\n",
*t, dh->dh_duration,
ETHER_ADDR(dh->dh_ra), ETHER_ADDR(dh->dh_ta),
index_, packet_info.name(ch->ptype()), ch->size());
}
void
Mac802_11::dump(char *fname)
{
fprintf(stderr,
"\n%s --- (INDEX: %d, time: %2.9f)\n",
fname, index_, Scheduler::instance().clock());
fprintf(stderr,
"\ttx_state_: %x, rx_state_: %x, nav: %2.9f, idle: %d\n",
tx_state_, rx_state_, nav_, is_idle());
fprintf(stderr,
"\tpktTx_: %x, pktRx_: %x, pktRTS_: %x, pktCTRL_: %x, callback: %x\n",
(int) pktTx_, (int) pktRx_, (int) pktRTS_,
(int) pktCTRL_, (int) callback_);
fprintf(stderr,
"\tDefer: %d, Backoff: %d (%d), Recv: %d, Timer: %d Nav: %d\n",
mhDefer_.busy(), mhBackoff_.busy(), mhBackoff_.paused(),
mhRecv_.busy(), mhSend_.busy(), mhNav_.busy());
fprintf(stderr,
"\tBackoff Expire: %f\n",
mhBackoff_.expire());
}
/* ======================================================================
Packet Headers Routines
====================================================================== */
inline int
Mac802_11::hdr_dst(char* hdr, int dst)
{
struct hdr_mac802_11* dh = (struct hdr_mac802_11*) hdr;
if (dst > -2) {
if ((bss_id() == IBSS_ID) || (addr() == bss_id())) {
/* if I'm AP (2nd condition above!), the dh_3a
* is already set by the MAC whilst fwding; if
* locally originated pkt, it might make sense
* to set the dh_3a to myself here! don't know
* how to distinguish between the two here - and
* the info is not critical to the dst station
* anyway!
*/
STORE4BYTE(&dst, (dh->dh_ra));
} else {
/* in BSS mode, the AP forwards everything;
* therefore, the real dest goes in the 3rd
* address, and the AP address goes in the
* destination address
*/
STORE4BYTE(&bss_id_, (dh->dh_ra));
STORE4BYTE(&dst, (dh->dh_3a));
}
}
return ETHER_ADDR(dh->dh_ra);
}
inline int
Mac802_11::hdr_src(char* hdr, int src)
{
struct hdr_mac802_11* dh = (struct hdr_mac802_11*) hdr;
if (src > -2)
STORE4BYTE(&src, (dh->dh_ta));
return ETHER_ADDR(dh->dh_ta);
}
inline int
Mac802_11::hdr_type(char* hdr, u_int16_t type)
{
#define _hdr_type_set(_dh) \
((GET2BYTE((_dh)->dh_body) == ETHERTYPE_ARP) \
|| (GET2BYTE((_dh)->dh_body) == ETHERTYPE_IP))
struct hdr_mac802_11* dh = (struct hdr_mac802_11*)hdr;
/* HACK - AMAN! to cover the BSS case of fwding packets
* at the AP, via the LL
*/
if (type && !_hdr_type_set(dh))
STORE2BYTE(&type,(dh->dh_body));
return GET2BYTE(dh->dh_body);
}
/* ======================================================================
Misc Routines
====================================================================== */
inline int
Mac802_11::is_idle()
{
if (rx_state_ != MAC_IDLE)
return 0;
if (tx_state_ != MAC_IDLE)
return 0;
if (nav_ > Scheduler::instance().clock())
return 0;
return 1;
}
inline void
Mac802_11::set_nav(u_int16_t us, double eifs)
{
double now = Scheduler::instance().clock();
double t = now + (us * 1e-6);
if ((t + eifs) > nav_) {
if (t > (nav_ - eifs_nav_))
eifs_nav_ = eifs;
else
eifs_nav_ += t + eifs - nav_;
nav_ = t + eifs;
if (mhNav_.busy())
mhNav_.stop();
mhNav_.start(nav_ - now);
return;
}
if (t > (nav_ - eifs_nav_))
eifs_nav_ = nav_ - t;
}
inline void
Mac802_11::reset_eifs_nav()
{
if (eifs_nav_) {
double now = Scheduler::instance().clock();
assert(nav_ > now);
assert(mhNav_.busy());
mhNav_.stop();
nav_ -= eifs_nav_;
eifs_nav_ = 0.0;
if (nav_ > now) {
mhNav_.start(nav_ - now);
} else {
nav_ = now;
CHECK_BACKOFF_TIMER();
}
}
}
void
Mac802_11::discard(Packet *p, const char* why)
{
hdr_mac802_11* mh = HDR_MAC802_11(p);
hdr_cmn *ch = HDR_CMN(p);
#if 0
/* old logic 8/8/98 -dam */
/*
* If received below the RXThreshold, then just free.
*/
if (p->txinfo_.Pr < p->txinfo_.ant.RXThresh) {
Packet::free(p);
//p = 0;
return;
}
#endif // 0
/* if the rcvd pkt contains errors, a real MAC layer couldn't
necessarily read any data from it, so we just toss it now */
if (ch->error() != 0) {
Packet::free(p);
//p = 0;
return;
}
switch(mh->dh_fc.fc_type) {
case MAC_Type_Management:
drop(p, why);
//drop(p);
return;
case MAC_Type_Control:
switch(mh->dh_fc.fc_subtype) {
case MAC_Subtype_RTS:
if ((u_int32_t)ETHER_ADDR(mh->dh_ta) == \
(u_int32_t)index_) {
drop(p, why);
return;
}
/* fall through - if necessary */
case MAC_Subtype_CTS:
case MAC_Subtype_ACK:
if ((u_int32_t)ETHER_ADDR(mh->dh_ra) == \
(u_int32_t)index_) {
drop(p, why);
return;
}
break;
default:
fprintf(stderr, "invalid MAC Control subtype\n");
exit(1);
}
break;
case MAC_Type_Data:
switch(mh->dh_fc.fc_subtype) {
case MAC_Subtype_Data:
if ((u_int32_t)ETHER_ADDR(mh->dh_ra) == \
(u_int32_t)index_ ||
(u_int32_t)ETHER_ADDR(mh->dh_ta) == \
(u_int32_t)index_ ||
(u_int32_t)ETHER_ADDR(mh->dh_ra) == MAC_BROADCAST) {
drop(p, why);
return;
}
break;
default:
fprintf(stderr, "invalid MAC Data subtype\n");
exit(1);
}
break;
default:
fprintf(stderr, "invalid MAC type (%x)\n", mh->dh_fc.fc_type);
trace_pkt(p);
exit(1);
}
Packet::free(p);
//p = 0;
}
void
Mac802_11::capture(Packet *p)
{
/*
* Update the NAV so that this does not screw
* up carrier sense.
*/
set_nav(usec(TX_Time(p)), eifs_);
Packet::free(p);
}
void
Mac802_11::collision(Packet *p)
{
switch(rx_state_) {
case MAC_RECV:
SET_RX_STATE(MAC_COLL);
/* fall through */
case MAC_COLL:
assert(pktRx_);
assert(mhRecv_.busy());
/*
* Since a collision has occurred, figure out
* which packet that caused the collision will
* "last" the longest. Make this packet,
* pktRx_ and reset the Recv Timer if necessary.
*/
if (TX_Time(p) > mhRecv_.expire()) {
mhRecv_.stop();
discard(pktRx_, DROP_MAC_COLLISION);
pktRx_ = p;
mhRecv_.start(TX_Time(pktRx_));
}
else {
discard(p, DROP_MAC_COLLISION);
}
break;
default:
assert(0);
}
}
void
Mac802_11::tx_resume()
{
assert(mhSend_.busy() == 0);
assert(mhDefer_.busy() == 0);
if (pktCTRL_) {
/*
* Need to send a CTS or ACK.
*/
mhDefer_.start(sifs_);
}
else if (pktRTS_) {
if (mhBackoff_.busy() == 0)
mhDefer_.start(difs_);
}
else if (pktTx_) {
if (mhBackoff_.busy() == 0) {
if (((u_int32_t)HDR_CMN(pktTx_)->size() < macmib_->RTSThreshold) ||
((u_int32_t)ETHER_ADDR(HDR_MAC802_11(pktTx_)->dh_ra) == MAC_BROADCAST))
mhDefer_.start(difs_);
else
mhDefer_.start(sifs_);
}
}
else if (callback_) {
Handler *h = callback_;
callback_ = 0;
h->handle((Event*) 0);
}
SET_TX_STATE(MAC_IDLE);
}
void
Mac802_11::rx_resume()
{
assert(pktRx_ == 0);
assert(mhRecv_.busy() == 0);
SET_RX_STATE(MAC_IDLE);
}
/* ======================================================================
Timer Handler Routines
====================================================================== */
void
Mac802_11::backoffHandler()
{
if (pktCTRL_) {
assert(mhSend_.busy() || mhDefer_.busy());
return;
}
if (check_pktRTS() == 0)
return;
if (check_pktTx() == 0)
return;
}
void
Mac802_11::deferHandler()
{
assert(pktCTRL_ || pktRTS_ || pktTx_);
if (check_pktCTRL() == 0)
return;
assert(mhBackoff_.busy() == 0);
if (check_pktRTS() == 0)
return;
if (check_pktTx() == 0)
return;
}
void
Mac802_11::navHandler()
{
eifs_nav_ = 0.0;
CHECK_BACKOFF_TIMER();
}
void
Mac802_11::recvHandler()
{
recv_timer();
}
void
Mac802_11::sendHandler()
{
send_timer();
}
void
Mac802_11::txHandler()
{
mac_EOT(tx_active_);
tx_active_ = NULL;
}
/* ======================================================================
The "real" Timer Handler Routines
====================================================================== */
void
Mac802_11::send_timer()
{
switch(tx_state_) {
/*
* Sent a RTS, but did not receive a CTS.
*/
case MAC_RTS:
RetransmitRTS();
break;
/*
* Sent a CTS, but did not receive a DATA packet.
*/
case MAC_CTS:
assert(pktCTRL_);
Packet::free(pktCTRL_); pktCTRL_ = 0;
break;
/*
* Sent DATA, but did not receive an ACK packet.
*/
case MAC_SEND:
RetransmitDATA();
break;
/*
* Sent an ACK, and now ready to resume transmission.
*/
case MAC_ACK:
assert(pktCTRL_);
Packet::free(pktCTRL_); pktCTRL_ = 0;
break;
case MAC_IDLE:
break;
default:
assert(0);
}
tx_resume();
}
/* ======================================================================
Outgoing Packet Routines
====================================================================== */
int
Mac802_11::check_pktCTRL()
{
struct hdr_mac802_11 *mh;
double timeout;
if (pktCTRL_ == 0)
return -1;
if (tx_state_ == MAC_CTS || tx_state_ == MAC_ACK)
return -1;
mh = HDR_MAC802_11(pktCTRL_);
switch(mh->dh_fc.fc_subtype) {
/*
* If the medium is not IDLE, don't send the CTS.
*/
case MAC_Subtype_CTS:
if (!is_idle()) {
discard(pktCTRL_, DROP_MAC_BUSY); pktCTRL_ = 0;
return 0;
}
SET_TX_STATE(MAC_CTS);
timeout = DATATimeout(mh->dh_duration);
break;
/*
* IEEE 802.11 specs, section 9.2.8
* Acknowledments are sent after an SIFS, without regard to
* the busy/idle state of the medium.
*/
case MAC_Subtype_ACK:
SET_TX_STATE(MAC_ACK);
timeout = DATA_Time(ETHER_ACK_LEN);
break;
default:
fprintf(stderr, "check_pktCTRL:Invalid MAC Control subtype\n");
exit(1);
}
TRANSMIT(pktCTRL_, timeout);
return 0;
}
int
Mac802_11::check_pktRTS()
{
struct hdr_mac802_11 *mh;
double timeout;
assert(mhBackoff_.busy() == 0);
if (pktRTS_ == 0)
return -1;
mh = HDR_MAC802_11(pktRTS_);
switch(mh->dh_fc.fc_subtype) {
case MAC_Subtype_RTS:
if (!is_idle()) {
inc_cw();
mhBackoff_.start(cw_, is_idle());
return 0;
}
SET_TX_STATE(MAC_RTS);
timeout = CTSTimeout;
break;
default:
fprintf(stderr, "check_pktRTS:Invalid MAC Control subtype\n");
exit(1);
}
TRANSMIT(pktRTS_, timeout);
return 0;
}
int
Mac802_11::check_pktTx()
{
struct hdr_mac802_11 *mh;
double timeout;
assert(mhBackoff_.busy() == 0);
if (pktTx_ == 0)
return -1;
mh = HDR_MAC802_11(pktTx_);
int len = HDR_CMN(pktTx_)->size();
switch(mh->dh_fc.fc_subtype) {
case MAC_Subtype_Data:
if (!is_idle()) {
sendRTS(ETHER_ADDR(mh->dh_ra));
inc_cw();
mhBackoff_.start(cw_, is_idle());
return 0;
}
SET_TX_STATE(MAC_SEND);
if ((u_int32_t)ETHER_ADDR(mh->dh_ra) != MAC_BROADCAST)
timeout = ACKTimeout(len);
else
timeout = TX_Time(pktTx_);
break;
default:
fprintf(stderr, "check_pktTx:Invalid MAC Control subtype\n");
exit(1);
}
TRANSMIT(pktTx_, timeout);
return 0;
}
/*
* Low-level transmit functions that actually place the packet onto
* the channel.
*/
void
Mac802_11::sendRTS(int dst)
{
Packet *p = Packet::alloc();
hdr_cmn* ch = HDR_CMN(p);
struct rts_frame *rf = (struct rts_frame*)p->access(hdr_mac::offset_);
//struct hdr_mac802_11 *mh = HDR_MAC802_11(p);
assert(pktTx_);
assert(pktRTS_ == 0);
/*
* If the size of the packet is larger than the
* RTSThreshold, then perform the RTS/CTS exchange.
*
* XXX: also skip if destination is a broadcast
*/
if ( (u_int32_t) HDR_CMN(pktTx_)->size() < macmib_->RTSThreshold ||
(u_int32_t) dst == MAC_BROADCAST) {
Packet::free(p);
//p = 0;
return;
}
ch->uid() = 0;
ch->ptype() = PT_MAC;
ch->size() = ETHER_RTS_LEN;
ch->iface() = -2;
ch->error() = 0;
bzero(rf, MAC_HDR_LEN);
rf->rf_fc.fc_protocol_version = MAC_ProtocolVersion;
rf->rf_fc.fc_type = MAC_Type_Control;
rf->rf_fc.fc_subtype = MAC_Subtype_RTS;
rf->rf_fc.fc_to_ds = 0;
rf->rf_fc.fc_from_ds = 0;
rf->rf_fc.fc_more_frag = 0;
rf->rf_fc.fc_retry = 0;
rf->rf_fc.fc_pwr_mgt = 0;
rf->rf_fc.fc_more_data = 0;
rf->rf_fc.fc_wep = 0;
rf->rf_fc.fc_order = 0;
rf->rf_duration = RTS_DURATION(pktTx_);
//ETHER_ADDR(rf->rf_ra) = dst;
STORE4BYTE(&dst, (rf->rf_ra));
//ETHER_ADDR(rf->rf_ta) = index_;
STORE4BYTE(&index_, (rf->rf_ta));
// rf->rf_fcs;
pktRTS_ = p;
}
void
Mac802_11::sendCTS(int dst, double rts_duration)
{
Packet *p = Packet::alloc();
hdr_cmn* ch = HDR_CMN(p);
struct cts_frame *cf = (struct cts_frame*)p->access(hdr_mac::offset_);
//struct hdr_mac802_11 *mh = HDR_MAC802_11(p);
assert(pktCTRL_ == 0);
ch->uid() = 0;
ch->ptype() = PT_MAC;
ch->size() = ETHER_CTS_LEN;
ch->iface() = -2;
ch->error() = 0;
//ch->direction() = hdr_cmn::DOWN;
bzero(cf, MAC_HDR_LEN);
cf->cf_fc.fc_protocol_version = MAC_ProtocolVersion;
cf->cf_fc.fc_type = MAC_Type_Control;
cf->cf_fc.fc_subtype = MAC_Subtype_CTS;
cf->cf_fc.fc_to_ds = 0;
cf->cf_fc.fc_from_ds = 0;
cf->cf_fc.fc_more_frag = 0;
cf->cf_fc.fc_retry = 0;
cf->cf_fc.fc_pwr_mgt = 0;
cf->cf_fc.fc_more_data = 0;
cf->cf_fc.fc_wep = 0;
cf->cf_fc.fc_order = 0;
cf->cf_duration = CTS_DURATION(rts_duration);
//ETHER_ADDR(cf->cf_ra) = dst;
STORE4BYTE(&dst, (cf->cf_ra));
//STORE4BYTE(&dst, (mh->dh_ra));
// cf->cf_fcs;
pktCTRL_ = p;
}
void
Mac802_11::sendACK(int dst)
{
Packet *p = Packet::alloc();
hdr_cmn* ch = HDR_CMN(p);
struct ack_frame *af = (struct ack_frame*)p->access(hdr_mac::offset_);
//struct hdr_mac802_11 *mh = HDR_MAC802_11(p);
assert(pktCTRL_ == 0);
ch->uid() = 0;
ch->ptype() = PT_MAC;
ch->size() = ETHER_ACK_LEN;
ch->iface() = -2;
ch->error() = 0;
//ch->direction() = hdr_cmn::DOWN;
bzero(af, MAC_HDR_LEN);
af->af_fc.fc_protocol_version = MAC_ProtocolVersion;
af->af_fc.fc_type = MAC_Type_Control;
af->af_fc.fc_subtype = MAC_Subtype_ACK;
af->af_fc.fc_to_ds = 0;
af->af_fc.fc_from_ds = 0;
af->af_fc.fc_more_frag = 0;
af->af_fc.fc_retry = 0;
af->af_fc.fc_pwr_mgt = 0;
af->af_fc.fc_more_data = 0;
af->af_fc.fc_wep = 0;
af->af_fc.fc_order = 0;
af->af_duration = ACK_DURATION();
//ETHER_ADDR(af->af_ra) = dst;
STORE4BYTE(&dst, (af->af_ra));
// af->af_fcs;
pktCTRL_ = p;
}
void
Mac802_11::sendDATA(Packet *p)
{
hdr_cmn* ch = HDR_CMN(p);
struct hdr_mac802_11* dh = HDR_MAC802_11(p);
assert(pktTx_ == 0);
/*
* Update the MAC header
*/
ch->size() += ETHER_HDR_LEN;
dh->dh_fc.fc_protocol_version = MAC_ProtocolVersion;
dh->dh_fc.fc_type = MAC_Type_Data;
dh->dh_fc.fc_subtype = MAC_Subtype_Data;
//printf(".....p = %x, mac-subtype-%d\n",p,dh->dh_fc.fc_subtype);
/* For now - if we use a BSS all packets flow via the
* AP; if we use a IBSS there is no AP => there is no
* usefulness in setting the to_ds/from_ds fields! we
* need to set them only when we start sending direct
* packets in BSS mode also!
*/
dh->dh_fc.fc_to_ds = 0;
dh->dh_fc.fc_from_ds = 0;
dh->dh_fc.fc_more_frag = 0;
dh->dh_fc.fc_retry = 0;
dh->dh_fc.fc_pwr_mgt = 0;
dh->dh_fc.fc_more_data = 0;
dh->dh_fc.fc_wep = 0;
dh->dh_fc.fc_order = 0;
if ((u_int32_t)ETHER_ADDR(dh->dh_ra) != MAC_BROADCAST)
dh->dh_duration = DATA_DURATION();
else
dh->dh_duration = 0;
pktTx_ = p;
}
/* ======================================================================
Retransmission Routines
====================================================================== */
void
Mac802_11::RetransmitRTS()
{
assert(pktTx_);
assert(pktRTS_);
assert(mhBackoff_.busy() == 0);
macmib_->RTSFailureCount++;
ssrc_ += 1; // STA Short Retry Count
if (ssrc_ >= macmib_->ShortRetryLimit) {
discard(pktRTS_, DROP_MAC_RETRY_COUNT_EXCEEDED); pktRTS_ = 0;
/* tell the callback the send operation failed
before discarding the packet */
hdr_cmn *ch = HDR_CMN(pktTx_);
if (ch->xmit_failure_) {
/*
* Need to remove the MAC header so that
* re-cycled packets don't keep getting
* bigger.
*/
ch->size() -= ETHER_HDR_LEN;
ch->xmit_reason_ = XMIT_REASON_RTS;
ch->xmit_failure_(pktTx_->copy(),
ch->xmit_failure_data_);
}
discard(pktTx_, DROP_MAC_RETRY_COUNT_EXCEEDED); pktTx_ = 0;
ssrc_ = 0;
rst_cw();
}
else {
struct rts_frame *rf;
rf = (struct rts_frame*)pktRTS_->access(hdr_mac::offset_);
rf->rf_fc.fc_retry = 1;
inc_cw();
mhBackoff_.start(cw_, is_idle());
}
}
void
Mac802_11::RetransmitDATA()
{
struct hdr_cmn *ch;
struct hdr_mac802_11 *mh;
u_int32_t *rcount, *thresh;
assert(mhBackoff_.busy() == 0);
assert(pktTx_);
assert(pktRTS_ == 0);
ch = HDR_CMN(pktTx_);
mh = HDR_MAC802_11(pktTx_);
/*
* Broadcast packets don't get ACKed and therefore
* are never retransmitted.
*/
if ((u_int32_t)ETHER_ADDR(mh->dh_ra) == MAC_BROADCAST) {
Packet::free(pktTx_); pktTx_ = 0;
/*
* Backoff at end of TX.
*/
rst_cw();
mhBackoff_.start(cw_, is_idle());
return;
}
macmib_->ACKFailureCount++;
if ((u_int32_t) ch->size() <= macmib_->RTSThreshold) {
rcount = &ssrc_;
thresh = &macmib_->ShortRetryLimit;
}
else {
rcount = &slrc_;
thresh = &macmib_->LongRetryLimit;
}
(*rcount)++;
if (*rcount > *thresh) {
macmib_->FailedCount++;
/* tell the callback the send operation failed
before discarding the packet */
hdr_cmn *ch = HDR_CMN(pktTx_);
if (ch->xmit_failure_) {
ch->size() -= ETHER_HDR_LEN;
ch->xmit_reason_ = XMIT_REASON_ACK;
ch->xmit_failure_(pktTx_->copy(),
ch->xmit_failure_data_);
}
discard(pktTx_, DROP_MAC_RETRY_COUNT_EXCEEDED); pktTx_ = 0;
//printf("(%d)DATA discarded: count exceeded\n",index_);
*rcount = 0;
rst_cw();
}
else {
struct hdr_mac802_11 *dh;
dh = HDR_MAC802_11(pktTx_);
dh->dh_fc.fc_retry = 1;
sendRTS(ETHER_ADDR(mh->dh_ra));
inc_cw();
mhBackoff_.start(cw_, is_idle());
}
}
/* ======================================================================
Incoming Packet Routines
====================================================================== */
void
Mac802_11::send(Packet *p, Handler *h)
{
struct hdr_mac802_11* dh = HDR_MAC802_11(p);
/*
* drop the packet if the node is in sleep mode
XXX sleep mode can't stop node from sending packets
*/
if ((netif_->node())->sleep()) {
netif_->node()->set_node_sleep(0);
netif_->node()->set_node_state(INROUTE);
}
callback_ = h;
sendDATA(p);
sendRTS(ETHER_ADDR(dh->dh_ra));
/*
* Assign the data packet a sequence number.
*/
dh->dh_scontrol = sta_seqno_++;
if (is_idle()) {
/* call tx resume */
if (mhDefer_.busy() == 0) {
assert(!pktCTRL_);
tx_resume();
}
/* else do nothing */
return;
}
/* medium is busy;
* set backoff timer if not already set
*/
if (mhBackoff_.busy() == 0)
mhBackoff_.start(cw_, 0);
/* else do nothing */
}
void
Mac802_11::recv(Packet *p, Handler *h)
{
struct hdr_cmn *hdr = HDR_CMN(p);
/*
* Sanity Check
*/
assert(initialized());
/*
* Handle outgoing packets.
*/
if (hdr->direction() == hdr_cmn::DOWN) {
send(p, h);
return;
}
/*
* Handle incoming packets.
*
* We just received the 1st bit of a packet on the network
* interface.
*
*/
/*
* If the interface is currently in transmit mode, then
* it probably won't even see this packet. However, the
* "air" around me is BUSY so I need to let the packet
* proceed. Just set the error flag in the common header
* to that the packet gets thrown away.
*/
if (tx_active_ && hdr->error() == 0) {
hdr->error() = 1;
}
if (rx_state_ == MAC_IDLE) {
SET_RX_STATE(MAC_RECV);
pktRx_ = p;
/*
* Schedule the reception of this packet, in
* txtime seconds.
*/
mhRecv_.start(TX_Time(p));
}
else {
/*
* If the power of the incoming packet is smaller than the
* power of the packet currently being received by at least
* the capture threshold, then we ignore the new packet.
*/
if (pktRx_->txinfo_.RxPr / p->txinfo_.RxPr >= p->txinfo_.CPThresh) {
capture(p);
}
else {
collision(p);
}
}
}
void
Mac802_11::recv_timer()
{
u_int32_t src;
hdr_cmn *ch = HDR_CMN(pktRx_);
hdr_mac802_11 *mh = HDR_MAC802_11(pktRx_);
u_int32_t dst = ETHER_ADDR(mh->dh_ra);
u_int8_t type = mh->dh_fc.fc_type;
u_int8_t subtype = mh->dh_fc.fc_subtype;
assert(pktRx_);
assert(rx_state_ == MAC_RECV || rx_state_ == MAC_COLL);
/*
* If the interface is in TRANSMIT mode when this packet
* "arrives", then I would never have seen it and should
* do a silent discard without adjusting the NAV.
*/
if (tx_active_) {
Packet::free(pktRx_);
goto done;
}
/*
* Handle collisions.
*/
if (rx_state_ == MAC_COLL) {
discard(pktRx_, DROP_MAC_COLLISION);
set_nav(0, eifs_);
goto done;
}
/*
* Check to see if this packet was received with enough
* bit errors that the current level of FEC still could not
* fix all of the problems - ie; after FEC, the checksum still
* failed.
*/
if (ch->error()) {
Packet::free(pktRx_);
set_nav(0, eifs_);
goto done;
}
/* saw a valid pkt on the medium - reset any pending
* eifs_ period within our nav based scheme
*/
reset_eifs_nav();
/*
* IEEE 802.11 specs, section 9.2.5.6
* - update the NAV (Network Allocation Vector)
*/
if (dst != (u_int32_t)index_) {
set_nav(mh->dh_duration, 0);
}
/* tap out - */
if (tap_ && type == MAC_Type_Data &&
MAC_Subtype_Data == subtype )
tap_->tap(pktRx_);
/*
* Adaptive Fidelity Algorithm Support - neighborhood infomation collection
*
* Hacking: Before filter the packet, log the neighbor node
* I can hear the packet, the src is my neighbor
*/
if (netif_->node()->adaptivefidelity()) {
src = ETHER_ADDR(mh->dh_ta);
netif_->node()->add_neighbor(src);
}
/*
* Address Filtering
*/
if (dst != (u_int32_t)index_ && dst != MAC_BROADCAST) {
/*
* We don't want to log this event, so we just free
* the packet instead of calling the drop routine.
*/
discard(pktRx_, "---");
goto done;
}
switch(type) {
case MAC_Type_Management:
discard(pktRx_, DROP_MAC_PACKET_ERROR);
goto done;
break;
case MAC_Type_Control:
switch(subtype) {
case MAC_Subtype_RTS:
recvRTS(pktRx_);
break;
case MAC_Subtype_CTS:
recvCTS(pktRx_);
break;
case MAC_Subtype_ACK:
recvACK(pktRx_);
break;
default:
fprintf(stderr,"recvTimer1:Invalid MAC Control Subtype %x\n",
subtype);
exit(1);
}
break;
case MAC_Type_Data:
switch(subtype) {
case MAC_Subtype_Data:
recvDATA(pktRx_);
break;
default:
fprintf(stderr, "recv_timer2:Invalid MAC Data Subtype %x\n",
subtype);
exit(1);
}
break;
default:
fprintf(stderr, "recv_timer3:Invalid MAC Type %x\n", subtype);
exit(1);
}
done:
pktRx_ = 0;
rx_resume();
}
void
Mac802_11::recvRTS(Packet *p)
{
struct rts_frame *rf = (struct rts_frame*)p->access(hdr_mac::offset_);
if (tx_state_ != MAC_IDLE) {
discard(p, DROP_MAC_BUSY);
return;
}
/*
* If I'm responding to someone else, discard this RTS.
*/
if (pktCTRL_) {
discard(p, DROP_MAC_BUSY);
return;
}
sendCTS(ETHER_ADDR(rf->rf_ta), rf->rf_duration);
/*
* Stop deferring - will be reset in tx_resume().
*/
if (mhDefer_.busy()) mhDefer_.stop();
tx_resume();
mac_log(p);
}
void
Mac802_11::recvCTS(Packet *p)
{
if (tx_state_ != MAC_RTS) {
discard(p, DROP_MAC_INVALID_STATE);
return;
}
assert(pktRTS_);
Packet::free(pktRTS_); pktRTS_ = 0;
assert(pktTx_);
mhSend_.stop();
/*
* The successful reception of this CTS packet implies
* that our RTS was successful. Hence, we can reset
* the Short Retry Count and the CW.
*/
ssrc_ = 0;
rst_cw();
tx_resume();
mac_log(p);
}
void
Mac802_11::recvDATA(Packet* p)
{
struct hdr_cmn* ch = HDR_CMN(p);
struct hdr_mac802_11* dh = HDR_MAC802_11(p);
u_int32_t dst, src, size;
dst = ETHER_ADDR(dh->dh_ra);
src = ETHER_ADDR(dh->dh_ta);
size = ch->size();
/*
* Adjust the MAC packet size - ie; strip
* off the mac header
*/
ch->size() -= ETHER_HDR_LEN;
ch->num_forwards() += 1;
/*
* If we sent a CTS, clean up...
*/
if (dst != MAC_BROADCAST) {
if (size >= macmib_->RTSThreshold) {
if (tx_state_ == MAC_CTS) {
assert(pktCTRL_);
Packet::free(pktCTRL_);
pktCTRL_ = 0;
mhSend_.stop();
/*
* Our CTS got through.
*/
ssrc_ = 0;
rst_cw();
} else {
discard(p, DROP_MAC_BUSY);
return;
}
sendACK(src);
tx_resume();
} else {
/*
* We did not send a CTS and there's no
* room to buffer an ACK.
*/
if (pktCTRL_) {
discard(p, DROP_MAC_BUSY);
return;
}
sendACK(src);
if (mhSend_.busy() == 0)
tx_resume();
}
}
/* ============================================================
Make/update an entry in our sequence number cache.
============================================================ */
if (dst != MAC_BROADCAST) {
Host* h = &cache_[src];
if (h->seqno && h->seqno == dh->dh_scontrol) {
discard(p, DROP_MAC_DUPLICATE);
return;
}
h->seqno = dh->dh_scontrol;
}
/* in BSS mode, if a station receives a packet via
* the AP, and higher layers are interested in looking
* at the src address, we might need to put it at
* the right place - lest the higher layers end up
* believing the AP address to be the src addr! a quick
* grep didn't turn up any higher layers interested in
* the src addr though!
* anyway, here if I'm the AP and the destination
* address (in dh_3a) isn't me, then we have to fwd
* the packet; we pick the real destination and set
* set it up for the LL; we save the real src into
* the dh_3a field for the 'interested in the info'
* receiver; we finally push the packet towards the
* LL to be added back to my queue - accomplish this
* by reversing the direction!
*/
if ((bss_id() == addr()) && (ETHER_ADDR(dh->dh_ra) != MAC_BROADCAST)
&& (ETHER_ADDR(dh->dh_3a) != addr())) {
int dst = ETHER_ADDR(dh->dh_3a);
int src = ETHER_ADDR(dh->dh_ta);
/* if it is a broadcast pkt then send a copy up
* my stack also
*/
if (dst == MAC_BROADCAST) {
uptarget_->recv(p->copy(), (Handler*) 0);
}
ch->next_hop() = dst;
STORE4BYTE(&src, (dh->dh_3a));
ch->addr_type() = NS_AF_ILINK;
ch->direction() = hdr_cmn::DOWN;
} else {
p->incoming = 1;
}
/*
* Pass the packet up to the link-layer.
* XXX - we could schedule an event to account
* for this processing delay.
*/
uptarget_->recv(p, (Handler*) 0);
}
void
Mac802_11::recvACK(Packet *p)
{
struct hdr_cmn *ch = HDR_CMN(p);
if (tx_state_ != MAC_SEND) {
discard(p, DROP_MAC_INVALID_STATE);
return;
}
assert(pktTx_);
Packet::free(pktTx_); pktTx_ = 0;
mhSend_.stop();
/*
* The successful reception of this ACK packet implies
* that our DATA transmission was successful. Hence,
* we can reset the Short/Long Retry Count and the CW.
*/
if ((u_int32_t) ch->size() <= macmib_->RTSThreshold)
ssrc_ = 0;
else
slrc_ = 0;
/*
* Backoff before sending again.
*/
rst_cw();
assert(mhBackoff_.busy() == 0);
mhBackoff_.start(cw_, is_idle());
tx_resume();
mac_log(p);
}
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1997 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the Computer Systems
* Engineering Group at Lawrence Berkeley Laboratory.
* 4. Neither the name of the University nor of the Laboratory may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* Ported from CMU/Monarch's code, nov'98 -Padma.
wireless-mac-802_11.h
*/
#ifndef ns_mac_80211_h
#define ns_mac_80211_h
#include "mac-timers.h"
#include "marshall.h"
#define GET_ETHER_TYPE(x) GET2BYTE((x))
#define SET_ETHER_TYPE(x,y) {u_int16_t t = (y); STORE2BYTE(x,&t);}
/* ======================================================================
Frame Formats
====================================================================== */
#define MAC_ProtocolVersion 0x00
#define MAC_Type_Management 0x00
#define MAC_Type_Control 0x01
#define MAC_Type_Data 0x02
#define MAC_Type_Reserved 0x03
#define MAC_Subtype_RTS 0x0B
#define MAC_Subtype_CTS 0x0C
#define MAC_Subtype_ACK 0x0D
#define MAC_Subtype_Data 0x00
struct frame_control {
u_char fc_subtype : 4;
u_char fc_type : 2;
u_char fc_protocol_version : 2;
u_char fc_order : 1;
u_char fc_wep : 1;
u_char fc_more_data : 1;
u_char fc_pwr_mgt : 1;
u_char fc_retry : 1;
u_char fc_more_frag : 1;
u_char fc_from_ds : 1;
u_char fc_to_ds : 1;
};
struct rts_frame {
struct frame_control rf_fc;
u_int16_t rf_duration;
u_char rf_ra[ETHER_ADDR_LEN];
u_char rf_ta[ETHER_ADDR_LEN];
u_char rf_fcs[ETHER_FCS_LEN];
};
struct cts_frame {
struct frame_control cf_fc;
u_int16_t cf_duration;
u_char cf_ra[ETHER_ADDR_LEN];
u_char cf_fcs[ETHER_FCS_LEN];
};
struct ack_frame {
struct frame_control af_fc;
u_int16_t af_duration;
u_char af_ra[ETHER_ADDR_LEN];
u_char af_fcs[ETHER_FCS_LEN];
};
struct hdr_mac802_11 {
struct frame_control dh_fc;
u_int16_t dh_duration;
u_char dh_ra[ETHER_ADDR_LEN];
u_char dh_ta[ETHER_ADDR_LEN];
/* 802.11 spec: (to AP, from AP)
* (0,0): dh_bssid
* (0,1): dh_sa
* (1,*): dh_da
*/
u_char dh_3a[ETHER_ADDR_LEN];
u_int16_t dh_scontrol;
u_char dh_4a[ETHER_ADDR_LEN];
u_char dh_body[0]; // XXX Non-ANSI
u_char dh_fcs[ETHER_FCS_LEN];
};
/* ======================================================================
Definitions
====================================================================== */
#define ETHER_HDR_LEN \
(sizeof(struct hdr_mac802_11))
#define ETHER_RTS_LEN \
(sizeof(struct rts_frame))
#define ETHER_CTS_LEN \
(sizeof(struct cts_frame))
#define ETHER_ACK_LEN \
(sizeof(struct ack_frame))
#define PLCP_Time \
((phymib_->PreambleLength + phymib_->PLCPHeaderLength) / phymib_->MinimumBandwidth)
#define DATA_Time(___len) \
((8 * (___len) / bandwidth_) + PLCP_Time)
/*
* IEEE 802.11 Spec, section 9.2.5.7
* - After transmitting an RTS, a node waits CTSTimeout
* seconds for a CTS.
*
* IEEE 802.11 Spec, section 9.2.8
* - After transmitting DATA, a node waits ACKTimeout
* seconds for an ACK.
*
* IEEE 802.11 Spec, section 9.2.5.4
* - After hearing an RTS, a node waits NAVTimeout seconds
* before resetting its NAV. I've coined the variable
* NAVTimeout.
*
* DATATimeout is set based on the original NS code; I don't know the
* source of this value - Aman
*
*/
#define CTSTimeout \
((DATA_Time(ETHER_RTS_LEN) + DATA_Time(ETHER_CTS_LEN)) + 2 * sifs_)
#define DATATimeout(___dur) \
((___dur * 1e-6) + DATA_Time(ETHER_CTS_LEN))
#define ACKTimeout(___len) \
(DATA_Time(___len) + DATA_Time(ETHER_ACK_LEN) + sifs_ + difs_)
#define NAVTimeout \
(2 * phymib_->SIFSTime + DATA_Time(ETHER_CTS_LEN) + 2 * phymib->SlotTime)
#define RTS_DURATION(pkt) \
usec(sifs_ + DATA_Time(ETHER_CTS_LEN) + sifs_ + TX_Time(pkt) + sifs_ + DATA_Time(ETHER_ACK_LEN))
#define CTS_DURATION(d) \
usec((d * 1e-6) - (DATA_Time(ETHER_CTS_LEN) + sifs_))
#define DATA_DURATION() \
usec(DATA_Time(ETHER_ACK_LEN) + sifs_)
#define ACK_DURATION() 0x00 // we're not doing fragments now
/*
* IEEE 802.11 Spec, section 15.3.2
* - default values for the DSSS PHY MIB
*/
#define DSSS_CWMin 31
#define DSSS_CWMax 1023
#define DSSS_SlotTime 0.000020 // 20us
#define DSSS_CCATime 0.000015 // 15us
#define DSSS_RxTxTurnaroundTime 0.000005 // 5us
#define DSSS_SIFSTime 0.000010 // 10us
#define DSSS_PreambleLength 144 // 144 bits
#define DSSS_PLCPHeaderLength 48 // 48 bits
#define DSSS_MinimumBandwidth 1000000.0 // 1Mbit/sec
class PHY_MIB {
public:
u_int32_t CWMin;
u_int32_t CWMax;
double SlotTime;
double CCATime;
double RxTxTurnaroundTime;
double SIFSTime;
u_int32_t PreambleLength;
u_int32_t PLCPHeaderLength;
double MinimumBandwidth;
};
/*
* IEEE 802.11 Spec, section 11.4.4.2
* - default values for the MAC Attributes
*/
#define MAC_RTSThreshold 3000 // bytes
#define MAC_ShortRetryLimit 7 // retransmittions
#define MAC_LongRetryLimit 4 // retransmissions
#define MAC_FragmentationThreshold 2346 // bytes
#define MAC_MaxTransmitMSDULifetime 512 // time units
#define MAC_MaxReceiveLifetime 512 // time units
class MAC_MIB {
public:
// MACAddress;
// GroupAddresses;
u_int32_t RTSThreshold;
u_int32_t ShortRetryLimit;
u_int32_t LongRetryLimit;
u_int32_t FragmentationThreshold;
u_int32_t MaxTransmitMSDULifetime;
u_int32_t MaxReceiveLifetime;
// ManufacturerID;
// ProductID;
u_int32_t TransmittedFragmentCount;
u_int32_t MulticastTransmittedFrameCount;
u_int32_t FailedCount;
u_int32_t RetryCount;
u_int32_t MultipleRetryCount;
u_int32_t FrameDuplicateCount;
u_int32_t RTSSuccessCount;
u_int32_t RTSFailureCount;
u_int32_t ACKFailureCount;
u_int32_t ReceivedFragmentCount;
u_int32_t MulticastReceivedFrameCount;
u_int32_t FCSErrorCount;
};
/* ======================================================================
The following destination class is used for duplicate detection.
====================================================================== */
class Host {
public:
LIST_ENTRY(Host) link;
u_int32_t index;
u_int32_t seqno;
};
/* ======================================================================
The actual 802.11 MAC class.
====================================================================== */
class Mac802_11 : public Mac {
friend class DeferTimer;
friend class BackoffTimer;
friend class IFTimer;
friend class NavTimer;
friend class RxTimer;
friend class TxTimer;
public:
Mac802_11(PHY_MIB* p, MAC_MIB *m);
void recv(Packet *p, Handler *h);
inline int hdr_dst(char* hdr, int dst = -2);
inline int hdr_src(char* hdr, int src = -2);
inline int hdr_type(char* hdr, u_int16_t type = 0);
inline int bss_id() { return bss_id_; }
protected:
void backoffHandler(void);
void deferHandler(void);
void navHandler(void);
void recvHandler(void);
void sendHandler(void);
void txHandler(void);
/* the macaddr of my AP in BSS mode; for IBSS mode
* this is set to a reserved value IBSS_ID - the
* MAC_BROADCAST reserved value can be used for this
* purpose
*/
int bss_id_;
#define IBSS_ID MAC_BROADCAST
private:
int command(int argc, const char*const* argv);
/*
* Called by the timers.
*/
void recv_timer(void);
void send_timer(void);
int check_pktCTRL();
int check_pktRTS();
int check_pktTx();
/*
* Packet Transmission Functions.
*/
void send(Packet *p, Handler *h);
void sendRTS(int dst);
void sendCTS(int dst, double duration);
void sendACK(int dst);
void sendDATA(Packet *p);
void RetransmitRTS();
void RetransmitDATA();
/*
* Packet Reception Functions.
*/
void recvRTS(Packet *p);
void recvCTS(Packet *p);
void recvACK(Packet *p);
void recvDATA(Packet *p);
void capture(Packet *p);
void collision(Packet *p);
void discard(Packet *p, const char* why);
void rx_resume(void);
void tx_resume(void);
inline int is_idle(void);
inline void set_nav(u_int16_t us, double eifs);
inline void reset_eifs_nav();
/*
* Debugging Functions.
*/
void trace_pkt(Packet *p);
void dump(char* fname);
inline int initialized() {
return (phymib_ && macmib_ && cache_ && logtarget_ && EOTtarget_ && Mac::initialized());
}
void mac_EOT(Packet *p) {
EOTtarget_->recv(p, (Handler*) 0);
}
inline double TX_Time(Packet *p) {
double t = DATA_Time((HDR_CMN(p))->size());
if (t < 0.0) {
drop(p, "XXX");
exit(1);
}
return t;
}
inline void inc_cw() {
cw_ = (cw_ << 1) + 1;
if(cw_ > phymib_->CWMax)
cw_ = phymib_->CWMax;
}
inline void rst_cw() { cw_ = phymib_->CWMin; }
inline u_int16_t usec(double t) {
u_int16_t us = (u_int16_t)ceil(t *= 1e6);
return us;
/*
u_int16_t us = (u_int16_t)(t *= 1e6);
if(us < t) {
us++;
}
return us;
*/
}
protected:
PHY_MIB *phymib_;
MAC_MIB *macmib_;
private:
/*
* Mac Timers
*/
IFTimer mhIF_; // interface timer
NavTimer mhNav_; // NAV timer
RxTimer mhRecv_; // incoming packets
TxTimer mhSend_; // outgoing packets
DeferTimer mhDefer_; // defer timer
BackoffTimer mhBackoff_; // backoff timer
/* ============================================================
Internal MAC State
============================================================ */
double nav_; // Network Allocation Vector
double eifs_nav_; // Handling eifs_ via NAV
MacState rx_state_; // incoming state (MAC_RECV or MAC_IDLE)
MacState tx_state_; // outgoint state
Packet *tx_active_; // transmitter is ACTIVE
Packet *pktRTS_; // outgoing RTS packet
Packet *pktCTRL_; // outgoing non-RTS control packet
Packet *pktBeacon_; // outgoing Beacon
u_int32_t cw_; // Contention Window
u_int32_t ssrc_; // STA Short Retry Count
u_int32_t slrc_; // STA Long Retry Count
double sifs_; // Short Interface Space
double pifs_; // PCF Interframe Space
double difs_; // DCF Interframe Space
double eifs_; // Extended Interframe Space
double tx_sifs_;
double tx_pifs_;
double tx_difs_;
int min_frame_len_;
NsObject* EOTtarget_;
/* ============================================================
Duplicate Detection state
============================================================ */
u_int16_t sta_seqno_; // next seqno that I'll use
int cache_node_count_;
Host *cache_;
};
#endif /* __mac_80211_h__ */