/* -*- 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 Daedalus Research
* Group at the University of California Berkeley.
* 4. Neither the name of the University nor of the research group 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.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/mac/mac-multihop.cc,v 1.14 2000/11/02 22:46:37 johnh Exp $ (UCB)";
#endif
#include "template.h"
#include "channel.h"
#include "mac-multihop.h"
/*
* For debugging.
*/
void dump_iphdr(hdr_ip *iph)
{
printf("\tsrc = %d, ", iph->saddr());
printf("\tdst = %d\n", iph->daddr());
}
static class MultihopMacClass : public TclClass {
public:
MultihopMacClass() : TclClass("Mac/Multihop") {}
TclObject* create(int, const char*const*) {
return (new MultihopMac);
}
} class_mac_multihop;
MultihopMac::MultihopMac() : mode_(MAC_IDLE), peer_(0),
pendingPollEvent_(0), pkt_(0),
ph_(this), pah_(this), pnh_(this), pth_(this), bh_(this)
{
/* Bind a bunch of variables to access from Tcl */
bind_time("tx_rx_", &tx_rx_);
bind_time("rx_tx_", &rx_tx_);
bind_time("rx_rx_", &rx_rx_);
bind_time("backoffBase_", &backoffBase_);
backoffTime_ = backoffBase_;
}
/*
* Returns 1 iff the specified MAC is in the prescribed state, AND all
* the other MACs are IDLE.
*/
int MultihopMac::checkInterfaces(int state)
{
MultihopMac *p;
if (!(mode_ & state))
return 0;
else if (macList_ == 0)
return 1;
for (p = (MultihopMac *)macList_; p != this && p != NULL;
p = (MultihopMac *)(p->macList())) {
if (p->mode() != MAC_IDLE) {
return 0;
}
}
return 1;
}
/*
* Poll a peer node prior to a send. There can be at most one POLL
* outstanding from a node at any point in time. This is achieved implicitly
* because there can be at most one packet down from LL (thru IFQ) to this MAC.
*/
void MultihopMac::poll(Packet *p)
{
Scheduler& s = Scheduler::instance();
MultihopMac *pm = (MultihopMac*) getPeerMac(p);
PollEvent *pe = new PollEvent(pm, this);
pendingPollEvent_ = new PollEvent(pm, this);
pkt_ = p->copy(); /* local copy for poll retries */
double timeout = max(pm->rx_tx(), tx_rx_) + 4*pollTxtime(MAC_POLLSIZE);
s.schedule(&bh_, pendingPollEvent_, timeout);
/* If the other interfaces are idle, then go ahead, else not. */
if (checkInterfaces(MAC_IDLE)) {
mode_ = MAC_POLLING;
peer_ = pm;
s.schedule(pm->ph(), (Event *)pe, pollTxtime(MAC_POLLSIZE));
}
}
/*
* Handle a POLL request from a peer node's MAC.
*/
void
PollHandler::handle(Event *e)
{
PollEvent *pe = (PollEvent *) e;
Scheduler& s = Scheduler::instance();
MultihopMac* pm = mac_->peer(); /* sensible val only in MAC_RCV mode */
/*
* Send POLLACK if either IDLE or currently receiving
* from same mac as the poller.
*/
if (mac_->checkInterfaces(MAC_IDLE)) { // all interfaces must be IDLE
mac_->mode(MAC_RCV);
pm = pe->peerMac();
mac_->peer(pm);
PollEvent *pae = new PollEvent(pm, mac_); // POLLACK event
double t = mac_->pollTxtime(MAC_POLLACKSIZE) +
max(mac_->tx_rx(), pm->rx_tx());
s.schedule(pm->pah(), pae, t);
} else {
// printf("ignoring poll %d\n", mac_->label());
// could send NACKPOLL but don't (at least for now)
}
}
/*
* Handle a POLLACK from a peer node's MAC.
*/
void
PollAckHandler::handle(Event *e)
{
PollEvent *pe = (PollEvent *) e;
Scheduler& s = Scheduler::instance();
if (mac_->checkInterfaces(MAC_POLLING | MAC_IDLE)) {
mac_->backoffTime(mac_->backoffBase());
mac_->mode(MAC_SND);
mac_->peer(pe->peerMac());
s.cancel(mac_->pendingPE()); /* cancel pending timeout */
free(mac_->pendingPE()); // and free the event
mac_->pendingPE(NULL);
mac_->send(mac_->pkt()); /* send saved packet */
}
}
void
PollNackHandler::handle(Event *)
{
}
void
BackoffHandler::handle(Event *)
{
Scheduler& s = Scheduler::instance();
if (mac_->mode() == MAC_POLLING)
mac_->mode(MAC_IDLE);
double bTime = mac_->backoffTime(2*mac_->backoffTime());
bTime = (1+Random::integer(MAC_TICK)*1./MAC_TICK)*bTime +
2*mac_->backoffBase();
// printf("backing off %d\n", mac_->label());
s.schedule(mac_->pth(), mac_->pendingPE(), bTime);
}
void
PollTimeoutHandler::handle(Event *)
{
mac_->poll(mac_->pkt());
}
/*
* Actually send the data frame.
*/
void MultihopMac::send(Packet *p)
{
Scheduler& s = Scheduler::instance();
if (mode_ != MAC_SND)
return;
double txt = txtime(p);
hdr_mac::access(p)->txtime() = txt;
channel_->send(p, txt); // target is peer's mac handler
s.schedule(callback_, &intr_, txt); // callback to higher layer (LL)
mode_ = MAC_IDLE;
}
/*
* This is the call from the higher layer of the protocol stack (i.e., LL)
*/
void MultihopMac::recv(Packet* p, Handler *h)
{
if (h == 0) { /* from MAC classifier (pass pkt to LL) */
mode_ = MAC_IDLE;
Scheduler::instance().schedule(target_, p, delay_);
return;
}
callback_ = h;
hdr_mac* mh = hdr_mac::access(p);
mh->macSA() = addr_;
if (mh->ftype() == MF_ACK) {
mode_ = MAC_SND;
send(p);
} else {
mh->ftype() = MF_DATA;
poll(p); /* poll first */
}
}
syntax highlighted by Code2HTML, v. 0.9.1