[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__ */