/*
* Copyright (C) 2000 by the University of Southern California
* $Id: mip-reg.cc,v 1.10 2005/08/25 18:58:08 johnh Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
*
* The copyright of this module includes the following
* linking-with-specific-other-licenses addition:
*
* In addition, as a special exception, the copyright holders of
* this module give you permission to combine (via static or
* dynamic linking) this module with free software programs or
* libraries that are released under the GNU LGPL and with code
* included in the standard release of ns-2 under the Apache 2.0
* license or under otherwise-compatible licenses with advertising
* requirements (or modified versions of such code, with unchanged
* license). You may copy and distribute such a system following the
* terms of the GNU GPL for this module and the licenses of the
* other code concerned, provided that you include the source code of
* that other code when and as the GNU GPL requires distribution of
* source code.
*
* Note that people who make modified versions of this module
* are not obligated to grant this special exception for their
* modified versions; it is their choice whether to do so. The GNU
* General Public License gives permission to release a modified
* version without this exception; this exception also makes it
* possible to release a modified version which carries forward this
* exception.
*
*/
// $Header: /nfs/jade/vint/CVSROOT/ns-2/mobile/mip-reg.cc,v 1.10 2005/08/25 18:58:08 johnh Exp $
/*
* Copyright (c) Sun Microsystems, Inc. 1998 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 Sun Microsystems, Inc.
*
* 4. The name of the Sun Microsystems, Inc nor may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* SUN MICROSYSTEMS MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS
* SOFTWARE FOR ANY PARTICULAR PURPOSE. The software is provided "as is"
* without express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this software.
*/
// #ident "@(#)mip-reg.cc 1.4 98/08/30 SMI"
#include <template.h>
#include <mip.h>
#include <random.h>
#include <address.h>
#include <mobilenode.h>
#define AGENT_ADS_SIZE 48
#define REG_REQUEST_SIZE 52
int hdr_mip::offset_;
static class MIPHeaderClass : public PacketHeaderClass {
public:
MIPHeaderClass() : PacketHeaderClass("PacketHeader/MIP",
sizeof(hdr_mip)) {
bind_offset(&hdr_mip::offset_);
}
} class_miphdr;
static class MIPBSAgentClass : public TclClass {
public:
MIPBSAgentClass() : TclClass("Agent/MIPBS") {}
TclObject* create(int, const char*const*) {
return (new MIPBSAgent());
}
} class_mipbsagent;
MIPBSAgent::MIPBSAgent() : Agent(PT_UDP), beacon_(1.0),
bcast_target_(0), ragent_(0), timer_(this), adlftm_(~0)
{
bind("adSize_", &size_);
//bind("shift_", &shift_);
//bind("mask_", &mask_);
bind("ad_lifetime_", &adlftm_);
size_ = AGENT_ADS_SIZE;
seqno_ = -1;
}
void MIPBSAgent::recv(Packet* p, Handler *)
{
Tcl& tcl = Tcl::instance();
const char *objname = NULL;
NsObject *obj = NULL;
hdr_mip *miph = hdr_mip::access(p);
hdr_ip *iph = hdr_ip::access(p);
hdr_cmn *ch = hdr_cmn::access(p);
int nodeaddr = Address::instance().get_nodeaddr(addr());
switch (miph->type_) {
case MIPT_REG_REQUEST:
//if (miph->ha_ == (addr_ >> shift_ & mask_)) {
if (miph->ha_ == (Address::instance().get_nodeaddr(addr()))){
if (miph->ha_ == miph->coa_) { // back home
tcl.evalf("%s clear-reg %d", name_,
miph->haddr_);
}
else {
tcl.evalf("%s encap-route %d %d %lf", name_,
miph->haddr_, miph->coa_,
miph->lifetime_);
}
iph->dst() = iph->src();
miph->type_ = MIPT_REG_REPLY;
}
else {
//iph->dst() = iph->dst() & ~(~(nsaddr_t)0 << shift_) | (miph->ha_ & mask_) << shift_;
iph->daddr() = miph->ha_;
iph->dport() = 0;
}
iph->saddr() = addr();
iph->sport() = port();
// by now should be back to normal route
// if dst is the mobile
// also initialise forward counter to 0. otherwise routing
// agent is going to think pkt is looping and drop it!!
ch->num_forwards() = 0;
send(p, 0);
break;
case MIPT_REG_REPLY:
//assert(miph->coa_ == (addr_ >> shift_ & mask_));
assert(miph->coa_ == nodeaddr);
tcl.evalf("%s get-link %d %d", name_, nodeaddr, miph->haddr_);
//
// XXX hacking mobileip. all this should go away
// when mobileIP for sun-wired model is no longer reqd.
//
obj = (NsObject*)tcl.lookup(objname = tcl.result());
if (strlen(objname) == 0)
objname = "XXX";
tcl.evalf("%s decap-route %d %s %lf", name_, miph->haddr_,
objname, miph->lifetime_);
iph->src() = iph->dst();
//iph->dst() = iph->dst() & ~(~(nsaddr_t)0 << shift_) |(miph->haddr_ & mask_) << shift_;
iph->daddr() = miph->haddr_;
iph->dport() = 0;
if (obj == NULL)
obj = ragent_;
obj->recv(p, (Handler*)0);
break;
case MIPT_SOL:
//tcl.evalf("%s get-link %d %d", name_, addr_ >> shift_ & mask_,miph->haddr_);
tcl.evalf("%s get-link %d %d",name_,nodeaddr,miph->haddr_);
send_ads(miph->haddr_, (NsObject*)tcl.lookup(tcl.result()));
Packet::free(p);
break;
default:
Packet::free(p);
break;
}
}
void MIPBSAgent::timeout(int )
{
send_ads();
timer_.resched(beacon_);
}
int MIPBSAgent::command(int argc, const char*const* argv)
{
if (argc == 3) {
if (strcmp(argv[1], "beacon-period") == 0) {
beacon_ = atof(argv[2]);
timer_.resched(Random::uniform(0, beacon_));
return TCL_OK;
}
if (strcmp(argv[1], "bcast-target") == 0) {
bcast_target_ = (NsObject *)TclObject::lookup(argv[2]);
return TCL_OK;
}
if (strcmp(argv[1], "ragent") == 0) {
ragent_ = (NsObject *)TclObject::lookup(argv[2]);
return TCL_OK;
}
}
return (Agent::command(argc, argv));
}
void MIPBSAgent::send_ads(int dst, NsObject *target)
{
Packet *p = allocpkt();
hdr_mip *h = hdr_mip::access(p);
hdr_ip *iph = hdr_ip::access(p);
h->haddr_ = h->ha_ = -1;
//h->coa_ = addr_ >> shift_ & mask_;
h->coa_ = Address::instance().get_nodeaddr(addr());
h->type_ = MIPT_ADS;
h->lifetime_ = adlftm_;
h->seqno_ = ++seqno_;
if (dst != -1) {
iph->daddr() = dst;
iph->dport() = 0;
}
else {
// if bcast pkt
sendOutBCastPkt(p);
}
if (target == NULL) {
if (bcast_target_) bcast_target_->recv(p, (Handler*) 0);
else if (target_) target_->recv(p, (Handler*) 0);
else Packet::free(p); // drop; may log in future code
}
else target->recv(p, (Handler*)0);
}
void
MIPBSAgent::sendOutBCastPkt(Packet *p)
{
hdr_ip *iph = hdr_ip::access(p);
hdr_cmn *hdrc = hdr_cmn::access(p);
hdrc->next_hop_ = IP_BROADCAST;
hdrc->addr_type_ = NS_AF_INET;
iph->daddr() = IP_BROADCAST;
iph->dport() = 0;
}
void AgtListTimer::expire(Event *) {
a_->timeout(MIP_TIMER_AGTLIST);
}
static class MIPMHAgentClass : public TclClass {
public:
MIPMHAgentClass() : TclClass("Agent/MIPMH") {}
TclObject* create(int, const char*const*) {
return (new MIPMHAgent());
}
} class_mipmhagent;
MIPMHAgent::MIPMHAgent() : Agent(PT_UDP), ha_(-1), coa_(-1),
beacon_(1.0),bcast_target_(0),agts_(0),rtx_timer_(this),
agtlist_timer_(this),reglftm_(~0),adlftm_(0.0), node_ (0)
{
bind("home_agent_", &ha_);
bind("rreqSize_", &size_);
bind("reg_rtx_", ®_rtx_);
bind("reg_lifetime_", ®lftm_);
size_ = REG_REQUEST_SIZE;
seqno_ = -1;
}
void MIPMHAgent::recv(Packet* p, Handler *)
{
Tcl& tcl = Tcl::instance();
hdr_mip *miph = hdr_mip::access(p);
switch (miph->type_) {
case MIPT_REG_REPLY:
if (miph->coa_ != coa_) break; // not pending
tcl.evalf("%s update-reg %d", name_, coa_);
if (rtx_timer_.status() == TIMER_PENDING)
rtx_timer_.cancel();
break;
case MIPT_ADS:
{
AgentList **ppagts = &agts_, *ptr;
while (*ppagts) {
if ((*ppagts)->node_ == miph->coa_) break;
ppagts = &(*ppagts)->next_;
}
if (*ppagts) {
ptr = *ppagts;
*ppagts = ptr->next_;
ptr->expire_time_ = beacon_ +
Scheduler::instance().clock();
ptr->lifetime_ = miph->lifetime_;
ptr->next_ = agts_;
agts_ = ptr;
if (coa_ == miph->coa_) {
seqno_++;
reg();
}
}
else { // new ads
ptr = new AgentList;
ptr->node_ = miph->coa_;
ptr->expire_time_ = beacon_ +
Scheduler::instance().clock();
ptr->lifetime_ = miph->lifetime_;
ptr->next_ = agts_;
agts_ = ptr;
coa_ = miph->coa_;
// The MHagent now should update the Mobilenode
// about the changed coa_ : node updates its
// base-station to new coa_ accordingly.
if(node_)
node_->set_base_stn(coa_);
adlftm_ = miph->lifetime_;
seqno_++;
reg();
}
}
break;
default:
break;
}
Packet::free(p);
}
void MIPMHAgent::timeout(int tno)
{
switch (tno) {
case MIP_TIMER_SIMPLE:
reg();
break;
case MIP_TIMER_AGTLIST:
{
double now = Scheduler::instance().clock();
AgentList **ppagts = &agts_, *ptr;
int coalost = 0;
while (*ppagts) {
if ((*ppagts)->expire_time_ < now) {
ptr = *ppagts;
*ppagts = ptr->next_;
if (ptr->node_ == coa_) {
coa_ = -1;
coalost = 1;
}
delete ptr;
}
else ppagts = &(*ppagts)->next_;
}
agtlist_timer_.resched(beacon_);
if (coalost) {
seqno_++;
reg();
}
}
break;
default:
break;
}
}
int MIPMHAgent::command(int argc, const char*const* argv)
{
if (argc == 3) {
if (strcmp(argv[1], "beacon-period") == 0) {
beacon_ = atof(argv[2]);
timeout(MIP_TIMER_AGTLIST);
agtlist_timer_.resched(beacon_);
rtx_timer_.resched(Random::uniform(0, beacon_));
return TCL_OK;
}
else if (strcmp(argv[1], "bcast-target") == 0) {
bcast_target_ = (NsObject *)TclObject::lookup(argv[2]);
return TCL_OK;
}
else if (strcmp (argv[1], "node") == 0) {
node_ = (MobileNode*)TclObject::lookup(argv[2]);
if (node_ == 0) {
fprintf (stderr, "%s: %s lookup of %s failed\n", __FILE__, argv[1], argv[2]);
return TCL_ERROR;
}
return TCL_OK;
}
}
// later: agent solicitation (now done!), start of simulation, ...
return (Agent::command(argc, argv));
}
void MIPMHAgent::reg()
{
rtx_timer_.resched(reg_rtx_);
if (agts_ == 0) {
send_sols();
return;
}
if (coa_ < 0) {
coa_ = agts_->node_;
adlftm_ = agts_->lifetime_;
}
Tcl& tcl = Tcl::instance();
Packet *p = allocpkt();
hdr_ip *iph = hdr_ip::access(p);
//iph->dst() = iph->dst() & ~(~(nsaddr_t)0 << shift_) | (coa_ & mask_) << shift_;
iph->daddr() = coa_;
iph->dport() = 0;
hdr_mip *h = hdr_mip::access(p);
//h->haddr_ = addr_ >> shift_ & mask_;
h->haddr_ = Address::instance().get_nodeaddr(addr());
h->ha_ = ha_;
h->coa_ = coa_;
h->type_ = MIPT_REG_REQUEST;
h->lifetime_ = MIN(reglftm_, adlftm_);
h->seqno_ = seqno_;
tcl.evalf("%s get-link %d %d", name_, h->haddr_, coa_);
NsObject *target = (NsObject *)tcl.lookup(tcl.result());
if (target != NULL)
((NsObject *)tcl.lookup(tcl.result()))->recv(p, (Handler*) 0);
else
send(p, 0);
}
void MIPMHAgent::send_sols()
{
Packet *p = allocpkt();
hdr_mip *h = hdr_mip::access(p);
h->coa_ = -1;
//h->haddr_ = addr_ >> shift_ & mask_;
h->haddr_ = Address::instance().get_nodeaddr(addr());
h->ha_ = ha_;
h->type_ = MIPT_SOL;
h->lifetime_ = reglftm_;
h->seqno_ = seqno_;
sendOutBCastPkt(p);
if (bcast_target_)
bcast_target_->recv(p, (Handler*) 0);
else if (target_)
target_->recv(p, (Handler*) 0);
else
Packet::free(p); // drop; may log in future code
}
void MIPMHAgent::sendOutBCastPkt(Packet *p)
{
hdr_ip *iph = hdr_ip::access(p);
hdr_cmn *hdrc = hdr_cmn::access(p);
hdrc->next_hop_ = IP_BROADCAST;
hdrc->addr_type_ = NS_AF_INET;
iph->daddr() = IP_BROADCAST;
iph->dport() = 0;
}
syntax highlighted by Code2HTML, v. 0.9.1