sathandoff.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:19k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
  2. /*
  3.  * Copyright (c) 1999 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  * 3. All advertising materials mentioning features or use of this software
  15.  *    must display the following acknowledgement:
  16.  *      This product includes software developed by the MASH Research
  17.  *      Group at the University of California Berkeley.
  18.  * 4. Neither the name of the University nor of the Research Group may be
  19.  *    used to endorse or promote products derived from this software without
  20.  *    specific prior written permission.
  21.  *
  22.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32.  * SUCH DAMAGE.
  33.  *
  34.  * Contributed by Tom Henderson, UCB Daedalus Research Group, June 1999
  35.  */
  36. #ifndef lint
  37. static const char rcsid[] =
  38.     "@(#) $Header: /cvsroot/nsnam/ns-2/satellite/sathandoff.cc,v 1.11 2005/08/22 05:08:34 tomh Exp $";
  39. #endif
  40. #include "random.h"
  41. #include "sathandoff.h"
  42. #include "satlink.h"
  43. #include "satroute.h"
  44. #include "satposition.h"
  45. #include "satnode.h"
  46. #include "satgeometry.h"
  47. #include <math.h>
  48. static class LinkHandoffMgrClass : public TclClass {
  49. public:
  50.         LinkHandoffMgrClass() : TclClass("HandoffManager") {}
  51.         TclObject* create(int, const char*const*) {
  52.                 return (new LinkHandoffMgr());
  53.         }
  54. } class_link_handoff_manager;
  55. static class SatLinkHandoffMgrClass : public TclClass {
  56. public:
  57.         SatLinkHandoffMgrClass() : TclClass("HandoffManager/Sat") {}
  58.         TclObject* create(int, const char*const*) {
  59.                 return (new SatLinkHandoffMgr());
  60.         }
  61. } class_sat_link_handoff_manager;
  62. static class TermLinkHandoffMgrClass : public TclClass {
  63. public:
  64.         TermLinkHandoffMgrClass() : TclClass("HandoffManager/Term") {}
  65.         TclObject* create(int, const char*const*) {
  66.                 return (new TermLinkHandoffMgr());
  67.         }
  68. } class_term_link_handoff_manager;
  69. void SatHandoffTimer::expire(Event*)
  70. {                           
  71.         a_->handoff();  
  72. }                               
  73. void TermHandoffTimer::expire(Event*)
  74. {                           
  75.         a_->handoff();  
  76. }                               
  77. //////////////////////////////////////////////////////////////////////////////
  78. // class LinkHandoffMgr
  79. //////////////////////////////////////////////////////////////////////////////
  80. RNG LinkHandoffMgr::handoff_rng_;
  81. int LinkHandoffMgr::handoff_randomization_ = 0;
  82. LinkHandoffMgr::LinkHandoffMgr()
  83. {
  84. bind_bool("handoff_randomization_", &handoff_randomization_);
  85. }
  86. int LinkHandoffMgr::command(int argc, const char*const* argv)
  87. {
  88. if (argc == 2) {
  89. } else if (argc == 3) {
  90. if(strcmp(argv[1], "setnode") == 0) {
  91. node_ = (Node*) TclObject::lookup(argv[2]);
  92. if (node_ == 0)
  93. return TCL_ERROR;
  94. return TCL_OK;
  95. }
  96. }
  97. return (TclObject::command(argc, argv));
  98. }
  99. // Each crossseam satellite will have two net stacks-- at most one will
  100. // be occupied.  This procedure finds an unoccupied stack on the node.
  101. SatLinkHead* LinkHandoffMgr::get_peer_next_linkhead(SatNode* np)
  102. {
  103. LinkHead* lhp;
  104. SatLinkHead* slhp;
  105. for (lhp = np->linklisthead().lh_first; lhp; 
  106.     lhp = lhp->nextlinkhead() ) {
  107. slhp = (SatLinkHead*) lhp;
  108. if (slhp->type() == LINK_ISL_CROSSSEAM) {
  109. if (!slhp->phy_tx()->channel() && 
  110.     !slhp->phy_rx()->channel() ) 
  111. return slhp;
  112. }
  113. }
  114. printf("Error, couldn't find an empty crossseam stack for handoffn");
  115. return 0;
  116. }
  117. // This helper function assumes that the channel to which the link interface
  118. // is attached has one peer node (i.e., no other receive infs on channel)
  119. SatLinkHead* LinkHandoffMgr::get_peer_linkhead(SatLinkHead* slhp)
  120. {
  121. SatChannel *schan_;
  122. Phy *remote_phy_;
  123. Node *remote_node_;
  124. schan_ = (SatChannel*) slhp->phy_tx()->channel();
  125. if (schan_ == 0) {
  126. printf("Error:  get_peer_linkhead called for a non-");
  127. printf("connected link on node %dn", slhp->node()->address());
  128. return 0; // Link is not currently connected
  129. }
  130. remote_phy_ = schan_->ifhead_.lh_first; 
  131. if (remote_phy_ == 0) {
  132. printf("Error:  node %d's tx phy ", slhp->node()->address());
  133. printf("connected to channel with no receiversn");
  134. return 0;
  135. }
  136. remote_node_ = remote_phy_->head()->node();
  137. if (remote_phy_->nextchnl()) {
  138. printf("Error:  This ISL channel has more than one targetn");
  139. return 0;
  140. }
  141. return ( (SatLinkHead*) remote_phy_->head());
  142. }
  143. // This helper function assumes that the channel to which the link interface
  144. // is attached has one peer node (i.e., no other receive infs on channel)
  145. SatNode* LinkHandoffMgr::get_peer(SatLinkHead* slhp)
  146. {
  147. SatChannel *schan_;
  148. Phy *remote_phy_;
  149. schan_ = (SatChannel*) slhp->phy_tx()->channel();
  150. if (schan_ == 0)
  151. return 0; // Link is not currently connected
  152. remote_phy_ = schan_->ifhead_.lh_first; 
  153. if (remote_phy_ == 0) {
  154. // this is not an error as far as satellite GSL endpoints
  155. // appear to be concerned.
  156. // Commented out for drawing GSL links in dumpSats()
  157. // in satnode.cc
  158. // printf("Error:  node %d's tx phy ", slhp->node()->address());
  159. // printf("connected to channel with no receiversn");
  160. return 0;
  161. }
  162. if (remote_phy_->nextchnl()) {
  163. printf("Error:  This ISL channel has more than one targetn");
  164. return 0;
  165. }
  166. return ( (SatNode*) remote_phy_->head()->node());
  167. }
  168. //////////////////////////////////////////////////////////////////////////
  169. // class TermLinkHandoffMgr
  170. //////////////////////////////////////////////////////////////////////////
  171. double TermLinkHandoffMgr::elevation_mask_ = 0;
  172. int TermLinkHandoffMgr::term_handoff_int_ = 10;
  173. TermLinkHandoffMgr::TermLinkHandoffMgr() : timer_(this)
  174. {
  175. bind("elevation_mask_", &elevation_mask_);
  176. bind("term_handoff_int_", &term_handoff_int_);
  177. }
  178. // 
  179. // This is called each time the node checks to see if its link to a
  180. // polar satellite needs to be handed off.  
  181. // There are two cases:
  182. //     i) current link is up; check to see if it stays up or is handed off
  183. //     ii) current link is down; check to see if it can go up
  184. // If there are any changes, call for rerouting.  Finally, restart the timer. 
  185. //
  186. int TermLinkHandoffMgr::handoff()
  187. {
  188. coordinate sat_coord, earth_coord;
  189. SatLinkHead* slhp;
  190. SatNode *peer_; // Polar satellite at opposite end of the GSL
  191. SatNode *best_peer_ = 0; // Best found peer for handoff
  192. Node *nodep;  // Pointer used in searching the list of nodes
  193. PolarSatPosition *nextpos_;
  194. int link_changes_flag_ = FALSE; // Flag indicating change took place 
  195. int restart_timer_flag_ = FALSE; // Restart timer only if polar links
  196. double found_elev_ = 0;  //``Flag'' indicates whether handoff can occur 
  197. double best_found_elev_ = 0; 
  198. double mask_ = DEG_TO_RAD(TermLinkHandoffMgr::elevation_mask_);
  199. earth_coord = ((SatNode *)node_)->position()->coord();
  200. // Traverse the linked list of link interfaces
  201. for (slhp = (SatLinkHead*) node_->linklisthead().lh_first; slhp; 
  202.     slhp = (SatLinkHead*) slhp->nextlinkhead() ) {
  203. if (slhp->type() == LINK_GSL_GEO || 
  204.     slhp->type() == LINK_GENERIC)
  205. continue;
  206. if (slhp->type() != LINK_GSL_POLAR) {
  207. printf("Error: Terminal link type ");
  208. printf("not valid %d NOW %fn", slhp->type(), NOW);
  209. exit(1);
  210. }
  211. // The link is a GSL_POLAR link-- should be one receive 
  212. // interface on it
  213. restart_timer_flag_ = TRUE;
  214. peer_ = get_peer(slhp);
  215. if (peer_) {
  216. sat_coord = peer_->position()->coord();
  217. if (!SatGeometry::check_elevation(sat_coord, 
  218.     earth_coord, mask_) && slhp->linkup_) {
  219. slhp->linkup_ = FALSE;
  220. link_changes_flag_ = TRUE;
  221. // Detach receive link interface from channel
  222. // Next line removes phy from linked list
  223. //   of interfaces attached to channel
  224. slhp->phy_rx()->removechnl();
  225. // Set our channel pointers to NULL
  226. slhp->phy_tx()->setchnl(0);
  227. slhp->phy_rx()->setchnl(0);
  228. // wired-satellite integration
  229. if (SatRouteObject::instance().wiredRouting()) {
  230. Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", slhp->phy_tx()->node()->address(), peer_->address());
  231. // Must do this bidirectionally
  232. Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", peer_->address(), slhp->phy_tx()->node()->address());
  233. }
  234. }
  235. }
  236. if (!slhp->linkup_) {
  237. // If link is down, see if we can use another satellite
  238. // 
  239. // As an optimization, first check the next satellite 
  240. // coming over the horizon.  Next, consider all 
  241. // remaining satellites.
  242. // 
  243. if (peer_) {
  244. // Next satellite
  245. nextpos_ = ((PolarSatPosition*) 
  246.     peer_->position())->next();
  247. if (nextpos_) {
  248. sat_coord = nextpos_->coord();
  249. found_elev_ = SatGeometry::check_elevation(sat_coord, earth_coord, mask_);
  250. if (found_elev_)
  251. peer_ = (SatNode*) nextpos_->node();
  252. }
  253. }
  254. // Next, check all remaining satellites if not found
  255. if (!found_elev_) {
  256. for (nodep=Node::nodehead_.lh_first; nodep;
  257.     nodep = nodep->nextnode()) {
  258. if (!SatNode::IsASatNode(nodep->address()))
  259. continue;
  260. peer_ = (SatNode*) nodep;
  261. if (peer_->position() && 
  262.     (peer_->position()->type() != 
  263.     POSITION_SAT_POLAR))
  264.     continue;
  265. sat_coord = 
  266.     peer_->position()->coord();
  267. found_elev_ = SatGeometry::check_elevation(sat_coord, earth_coord, mask_);
  268. if (found_elev_ > best_found_elev_) {
  269.     best_peer_ = peer_;
  270.     best_found_elev_ = found_elev_;
  271. }
  272. }
  273. if (best_found_elev_ > 0.0) {
  274. assert (best_peer_ != 0);
  275. peer_ = best_peer_;
  276. found_elev_ = best_found_elev_;
  277. }
  278. }
  279. if (found_elev_) {
  280. slhp->linkup_ = TRUE;
  281. link_changes_flag_ = TRUE;
  282. // Point slhp->phy_tx to peer_'s inlink
  283. slhp->phy_tx()->setchnl(peer_->uplink());
  284. // Point slhp->phy_rx to peer_'s outlink and
  285. // add phy_rx to the channels list of phy's
  286. slhp->phy_rx()->setchnl(peer_->downlink());
  287. // Add phy to channel's linked list of i/fces
  288. slhp->phy_rx()->insertchnl(&(peer_->downlink()->ifhead_));
  289. }
  290. }
  291. }
  292. if (link_changes_flag_) { 
  293. SatRouteObject::instance().recompute();
  294. }
  295. if (restart_timer_flag_) {
  296. // If we don't have polar GSLs, don't reset the timer
  297. if (handoff_randomization_) {
  298. timer_.resched(term_handoff_int_ + 
  299.     handoff_rng_.uniform(-1 * term_handoff_int_/2, 
  300.     term_handoff_int_/2));
  301. } else
  302. timer_.resched(term_handoff_int_);
  303. }
  304.         return link_changes_flag_;
  305. }
  306. //////////////////////////////////////////////////////////////////////////
  307. // class SatLinkHandoffMgr
  308. //////////////////////////////////////////////////////////////////////////
  309. double SatLinkHandoffMgr::latitude_threshold_ = 0;
  310. double SatLinkHandoffMgr::longitude_threshold_ = 0;
  311. int SatLinkHandoffMgr::sat_handoff_int_ = 10;
  312. SatLinkHandoffMgr::SatLinkHandoffMgr() : timer_(this)
  313. {
  314. bind("sat_handoff_int_", &sat_handoff_int_);
  315. bind("latitude_threshold_", &latitude_threshold_);
  316. bind("longitude_threshold_", &longitude_threshold_);
  317. }
  318. //
  319. // This function is responsible for activating, deactivating, and handing off
  320. // satellite ISLs.  If the ISL is an intraplane link, 
  321. // do nothing.  If the ISL is an interplane link, it will be taken down
  322. // when _either_ of the connected satellites are above lat_threshold_ 
  323. // degrees, and brought back up when _both_ satellites move below 
  324. // lat_threshold_ again.  If an ISL is a cross-seam link, it must also be 
  325. // handed off periodically while the satellite is below lat_threshold_.  
  326. // 
  327. // Finally, optimizations that avoid going through the linked lists unless 
  328. // the satellite is ``close'' to lat_threshold_ are employed.
  329. //
  330. int SatLinkHandoffMgr::handoff()
  331. {
  332. SatLinkHead *slhp, *peer_slhp, *peer_next_slhp;
  333. SatNode *local_, *peer_, *peer_next_; 
  334. PolarSatPosition *pos_, *peer_pos_, *peer_next_pos_;
  335. double dist_to_peer, dist_to_next;
  336. Channel *tx_channel_, *rx_channel_;
  337. double sat_latitude_, sat_longitude_, peer_latitude_, peer_longitude_;
  338. int link_down_flag_;
  339. double lat_threshold_ = DEG_TO_RAD(latitude_threshold_);
  340. double cross_long_threshold_ = DEG_TO_RAD(longitude_threshold_);
  341. int link_changes_flag_ = FALSE; // Flag indicating change took place 
  342. coordinate local_coord_, peer_coord_;
  343. local_ = (SatNode*) node_;
  344. local_coord_ = local_->position()->coord();
  345. sat_latitude_ = SatGeometry::get_latitude(local_->position()->coord());
  346. sat_longitude_= SatGeometry::get_longitude(local_->position()->coord());
  347. // First go through crossseam ISLs to search for handoffs
  348. for (slhp = (SatLinkHead*) local_->linklisthead().lh_first; slhp; 
  349.     slhp = (SatLinkHead*) slhp->nextlinkhead() ) {
  350. if (slhp->type() != LINK_ISL_CROSSSEAM)  
  351. continue;
  352. peer_ = get_peer(slhp);
  353. if (peer_ == 0)
  354. continue; // this link interface is not attached
  355. // If this is a crossseam link, first see if the link must 
  356. // be physically handed off to the next satellite.
  357. // Handoff is needed if the satellite at the other end of
  358. // the link is further away than the ``next'' satellite
  359. // in the peer's orbital plane.
  360. pos_ = (PolarSatPosition*)slhp->node()->position(); 
  361. peer_slhp = get_peer_linkhead(slhp);
  362. peer_pos_ = (PolarSatPosition*) peer_->position();
  363. peer_coord_ = peer_pos_->coord();
  364. if (fabs(sat_latitude_) > lat_threshold_)
  365. link_down_flag_ = TRUE;
  366. else
  367. link_down_flag_ = FALSE;
  368. if (peer_pos_->plane() < pos_->plane()) {
  369. // Crossseam handoff is controlled by satellites
  370. // in the plane with a lower index
  371. break;  
  372. }
  373. peer_next_pos_ = peer_pos_->next();
  374. if (!peer_next_pos_) {
  375. printf("Error:  crossseam handoffs require ");
  376. printf("setting the ``next'' fieldn");
  377. exit(1);
  378. }
  379. peer_next_ = (SatNode*) peer_next_pos_->node();
  380. dist_to_peer = SatGeometry::distance(peer_coord_, local_coord_);
  381. dist_to_next = SatGeometry::distance(peer_next_pos_->coord(), 
  382.     local_coord_); 
  383. if (dist_to_next < dist_to_peer) {
  384. // Handoff -- the "next" satellite should have a 
  385. // currently unused network stack.  Find this 
  386. // unused stack and handoff the channels to it.
  387. // 
  388.   // Remove peer's tx/rx interface from channel
  389. peer_slhp->phy_rx()->removechnl();
  390. peer_slhp->phy_tx()->setchnl(0);
  391. peer_slhp->phy_rx()->setchnl(0);
  392. // Add peer_next's tx/rx interfaces to our channels
  393. peer_next_slhp = get_peer_next_linkhead(peer_next_);
  394. tx_channel_ = slhp->phy_tx()->channel();
  395. rx_channel_ = slhp->phy_rx()->channel();
  396.                         peer_next_slhp->phy_tx()->setchnl(rx_channel_);
  397. peer_next_slhp->phy_rx()->setchnl(tx_channel_);
  398. peer_next_slhp->phy_rx()->insertchnl(&(tx_channel_->ifhead_));
  399. link_changes_flag_ = TRUE; 
  400. // wired-satellite integration
  401. if (SatRouteObject::instance().wiredRouting()) {
  402. // Check if link is up first before deleting
  403. if (slhp->linkup_) { 
  404. Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", slhp->phy_tx()->node()->address(), peer_->address());
  405. }
  406. if (peer_slhp->linkup_) { 
  407. Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", peer_->address(), slhp->phy_tx()->node()->address());
  408. }
  409. }
  410. // Now reset the peer_ variables to point to next
  411. peer_ = peer_next_;
  412. peer_slhp = peer_next_slhp;
  413. peer_coord_ = peer_->position()->coord();
  414. }
  415. // Next, see if the link needs to be taken down.
  416. peer_latitude_ = 
  417.     SatGeometry::get_latitude(peer_coord_);
  418. peer_longitude_ = SatGeometry::get_longitude(peer_coord_);
  419. if (fabs(peer_latitude_) > lat_threshold_)
  420. link_down_flag_ = TRUE;
  421. // If the two satellites are too close to each other in
  422. // longitude, the link should be down
  423. if ((fabs(peer_longitude_ - sat_longitude_) <
  424.     cross_long_threshold_) ||
  425.     fabs(peer_longitude_ - sat_longitude_) >
  426.     (2 * PI - cross_long_threshold_))
  427. link_down_flag_ = TRUE;
  428. // Check to see if link grazes atmosphere at an altitude
  429. // below the atmospheric margin
  430. link_down_flag_ |= !(SatGeometry::are_satellites_mutually_visible(peer_coord_, local_coord_));
  431. // Evaluate whether a change in link status is needed
  432. if ((slhp->linkup_ || peer_slhp->linkup_) && link_down_flag_) {
  433. slhp->linkup_ = FALSE;
  434. peer_slhp->linkup_ = FALSE;
  435. link_changes_flag_ = TRUE;
  436. // wired-satellite integration
  437. if (SatRouteObject::instance().wiredRouting()) {
  438.     Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", slhp->phy_tx()->node()->address(), peer_->address());
  439.     Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", peer_->address(), slhp->phy_tx()->node()->address());
  440. }
  441. } else if ((!slhp->linkup_  || !peer_slhp->linkup_) && 
  442.     !link_down_flag_) {
  443. slhp->linkup_ = TRUE;
  444. peer_slhp->linkup_ = TRUE;
  445. link_changes_flag_ = TRUE;
  446. }
  447. }
  448. // Now, work on interplane ISLs (intraplane ISLs are not handed off)
  449. // Now search for interplane ISLs
  450. for (slhp = (SatLinkHead*) local_->linklisthead().lh_first; slhp; 
  451.     slhp = (SatLinkHead*) slhp->nextlinkhead() ) {
  452. if (slhp->type() != LINK_ISL_INTERPLANE)  
  453. continue;
  454. if (fabs(sat_latitude_) > lat_threshold_)
  455. link_down_flag_ = TRUE;
  456. else
  457. link_down_flag_ = FALSE;
  458. peer_ = get_peer(slhp);
  459. peer_slhp = get_peer_linkhead(slhp);
  460. peer_coord_ = peer_->position()->coord();
  461. peer_latitude_ = SatGeometry::get_latitude(peer_coord_);
  462. if (fabs(peer_latitude_) > lat_threshold_)
  463. link_down_flag_ = TRUE;
  464. link_down_flag_ |= !(SatGeometry::are_satellites_mutually_visible(peer_coord_, local_coord_));
  465. if (slhp->linkup_ && link_down_flag_) {
  466. // Take links down if either satellite at high latitude
  467. slhp->linkup_ = FALSE;
  468. peer_slhp->linkup_ = FALSE;
  469. link_changes_flag_ = TRUE;
  470. // wired-satellite integration
  471. if (SatRouteObject::instance().wiredRouting()) {
  472.     Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", slhp->phy_tx()->node()->address(), peer_->address());
  473.     Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", peer_->address(), slhp->phy_tx()->node()->address());
  474. }                                                       
  475. } else if (!slhp->linkup_ && !link_down_flag_) {
  476. slhp->linkup_ = TRUE;
  477. peer_slhp->linkup_ = TRUE;
  478. link_changes_flag_ = TRUE;
  479. }
  480. }
  481. if (link_changes_flag_)  {
  482. SatRouteObject::instance().recompute();
  483. }
  484. if (handoff_randomization_) {
  485. timer_.resched(sat_handoff_int_ + 
  486.     handoff_rng_.uniform(-1 * sat_handoff_int_/2, 
  487.     sat_handoff_int_/2));
  488. } else
  489. timer_.resched(sat_handoff_int_);
  490. return link_changes_flag_;
  491. }