extern "C" { #include #include #include #include #include #include }; #include #include #include #include #include "noah.h" #define NOAH_BROADCAST_JITTER 0.01 // jitter for all broadcast packets //#define NOAH_DEBUG // Returns a random number between 0 and max static inline double jitter (double max, int be_random_) { return (be_random_ ? Random::uniform(max) : 0); } void NOAH_Agent::trace (char *fmt,...) { va_list ap; if (!tracetarget) return; va_start (ap, fmt); vsprintf (tracetarget->buffer (), fmt, ap); tracetarget->dump (); va_end (ap); } void NOAH_Agent::lost_link (Packet *p) { hdr_cmn *ch = HDR_CMN (p); if(use_mac_ == 0) { drop(p, DROP_RTR_MAC_CALLBACK); return; } if (!use_mac_ || ch->addr_type_ != NS_AF_INET) return; // Queue these packets up... recv(p, 0); } static void mac_callback (Packet * p, void *arg) { ((NOAH_Agent *) arg)->lost_link (p); } void NOAH_Agent::forwardPacket (Packet * p) { Scheduler & s = Scheduler::instance (); double now = s.clock (); hdr_cmn *ch = HDR_CMN (p); hdr_ip *iph = HDR_IP(p); if (node_->base_stn() == node_->address()) { // node is its own BS --> HA or FA ch->next_hop_ = Address::instance().get_nodeaddr(iph->daddr()); } else { // MH sends to BS // JCW set next hop in mip-reg.cc when sending request etc. // don't set when destination already set by MIPMH if (ch->next_hop_ <= -2) // see packet.h ch->next_hop_ = Address::instance().get_nodeaddr(node_->base_stn()); } ch->direction() = hdr_cmn::DOWN; ch->addr_type_ = NS_AF_INET; ch->xmit_failure_ = mac_callback; ch->xmit_failure_data_ = this; assert (!HDR_CMN (p)->xmit_failure_ || HDR_CMN (p)->xmit_failure_ == mac_callback); #ifdef NOAH_DEBUG printf("%f NOAH forward (node %s) to %s (via %s), packet %i\n", Scheduler::instance().clock(), Address::instance().print_nodeaddr(node_->address()), Address::instance().print_nodeaddr(iph->daddr()), Address::instance().print_nodeaddr(ch->next_hop_), ch->uid()); // JCW #endif target_->recv(p, (Handler *)0); return; } void NOAH_Agent::sendOutBCastPkt(Packet *p) { Scheduler & s = Scheduler::instance (); #ifdef NOAH_DEBUG hdr_ip *iph = HDR_IP(p); hdr_cmn *ch = HDR_CMN(p); printf("%f NOAH broadcast (node %s) to %s, packet %i\n", Scheduler::instance().clock(), Address::instance().print_nodeaddr(node_->address()), Address::instance().print_nodeaddr(iph->daddr()), ch->uid()); // JCW #endif s.schedule (target_, p, jitter(NOAH_BROADCAST_JITTER, be_random_)); } void NOAH_Agent::recv (Packet * p, Handler *) { hdr_ip *iph = HDR_IP(p); hdr_cmn *ch = HDR_CMN(p); int src = Address::instance().get_nodeaddr(iph->saddr()); int dst = ch->next_hop(); /* * Must be a packet I'm originating... */ if(src == myaddr_ && ch->num_forwards() == 0) { /* * Add the IP Header */ ch->size() += IP_HDR_LEN; iph->ttl_ = IP_DEF_TTL; } /* * I received a packet that I sent. Probably * a routing loop. */ else if(src == myaddr_) { #ifdef NOAH_DEBUG printf("%f NOAH dropped packet (routing loop)\n", Scheduler::instance().clock()); #endif drop(p, DROP_RTR_ROUTE_LOOP); return; } /* * Packet I'm forwarding... */ else { /* * Check the TTL. If it is zero, then discard. */ if(--iph->ttl_ == 0) { #ifdef NOAH_DEBUG printf("%f NOAH dropped packet (TTL)\n", Scheduler::instance().clock()); #endif drop(p, DROP_RTR_TTL); return; } } if ((u_int32_t) dst == IP_BROADCAST && (iph->dport() != ROUTER_PORT)) { if (src == myaddr_) { // handle brdcast pkt sendOutBCastPkt(p); } else { // hand it over to the port-demux #ifdef NOAH_DEBUG printf("%f NOAH receive (node %s) from %s, packet %i\n", Scheduler::instance().clock(), Address::instance().print_nodeaddr(node_->address()), Address::instance().print_nodeaddr(iph->daddr()), ch->uid()); // JCW #endif port_dmux_->recv(p, (Handler*)0); } } else { forwardPacket(p); } } static class NOAHClass:public TclClass { public: NOAHClass ():TclClass ("Agent/NOAH") {} TclObject *create (int, const char *const *) { return (new NOAH_Agent ()); } } class_noah; NOAH_Agent::NOAH_Agent (): Agent (PT_MESSAGE), myaddr_ (0), subnet_ (0), node_ (0), port_dmux_(0), be_random_ (1), use_mac_ (0) { bind ("use_mac_", &use_mac_); bind ("be_random_", &be_random_); } int NOAH_Agent::command (int argc, const char *const *argv) { if (argc == 3) { if (strcasecmp (argv[1], "addr") == 0) { myaddr_ = Address::instance().str2addr(argv[2]); subnet_ = Address::instance().get_subnetaddr(myaddr_); return TCL_OK; } TclObject *obj; if ((obj = TclObject::lookup (argv[2])) == 0) { fprintf (stderr, "%s: %s lookup of %s failed\n", __FILE__, argv[1], argv[2]); return TCL_ERROR; } if (strcasecmp (argv[1], "tracetarget") == 0) { tracetarget = (Trace *) obj; return TCL_OK; } else if (strcasecmp (argv[1], "node") == 0) { node_ = (MobileNode*) obj; return TCL_OK; } else if (strcasecmp (argv[1], "port-dmux") == 0) { port_dmux_ = (NsObject *) obj; return TCL_OK; } } return (Agent::command (argc, argv)); }