mn.c

Go to the documentation of this file.
00001 /* $Id: mn.c,v 1.239 2001/10/20 14:44:19 jm Exp $
00002  * Mobile Node - state machine and main loop
00003  *
00004  * Dynamic hierarchial IP tunnel
00005  * Copyright (C) 1998-2001, Dynamics group
00006  *
00007  * This program is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License version 2 as
00009  * published by the Free Software Foundation. See README and COPYING for
00010  * more details.
00011  */
00012 
00013 #ifdef HAVE_CONFIG_H
00014 #include <config.h>
00015 #endif
00016 
00017 #include <sys/types.h>
00018 #include <sys/socket.h>
00019 #include <netinet/in.h>
00020 #include <string.h>
00021 #include <stdio.h>
00022 #include <arpa/inet.h>
00023 #include <stdlib.h>
00024 #include <time.h>
00025 #include <assert.h>
00026 #include <errno.h>
00027 #include <unistd.h>
00028 
00029 #include "agentapi.h"
00030 #include "debug.h"
00031 #include "util.h"
00032 #include "dyn_ip.h"
00033 #include "mn.h"
00034 #ifndef DYN_TARGET_WINDOWS
00035 #include "monitor.h"
00036 #endif /* DYN_TARGET_WINDOWS */
00037 #include "fixed_fd_zero.h"
00038 #ifdef INCLUDE_IPAY
00039 #include "mn_ipay.h"
00040 #endif
00041 
00042 extern int real_tunnel_up; /* from mn_tunnel */
00043 
00044 struct mn_data mn;
00045 struct mn_config config; /* configuration information */
00046 /* Timers containing ending time for the timer */
00047 struct timeval timers[TIMER_COUNT];
00048 char *program_name;
00049 
00050 /*
00051  * Determine the timeout value in seconds for a solicitation request.
00052  * Parameters:
00053  *  counter - pointer to variable holding information,
00054  *            how many requests have been sent.
00055  * Returns: timeout in seconds or zero when it's time to go passive mode.
00056  */
00057 static int get_solicitation_interval(int *counter)
00058 {
00059         static int intervals[] = SOLICITATION_INTERVALS;
00060         int t;
00061 
00062         ASSERT(counter != NULL);
00063         ASSERT(sizeof(intervals) > 0);
00064 
00065         if (*counter < 0) *counter = 0;
00066 
00067         if (*counter >= sizeof(intervals) / sizeof(int))
00068                 t = 0;
00069         else t = intervals[*counter];
00070 
00071         (*counter)++;
00072 
00073         return t;
00074 
00075 }
00076 
00077 /*
00078  * Due to the unsuccessful registration to the FA, degrade its priority.
00079  */
00080 int degrade_current_fa_priority(void)
00081 {
00082         if (mn.current_adv == NULL)
00083                 return 1;
00084 
00085         if (mn.current_adv->prio_degrade_percent == 0) {
00086                 mn.current_adv->prio_degrade_percent = 
00087                         DEFAULT_PRIO_DEGRADE_INITIAL;
00088         } else {
00089                 mn.current_adv->prio_degrade_percent *= 
00090                         DEFAULT_PRIO_DEGRADE_FACTOR;
00091         }
00092 
00093         if (mn.current_adv->prio_degrade_percent > 100) {
00094                 mn.current_adv->prio_degrade_percent = 100;
00095         }
00096 
00097         DEBUG(DEBUG_INFO, "degrade_current_fa_priority: %d\n",
00098               mn.current_adv->prio_degrade_percent);
00099         
00100         return 0;
00101 }
00102 
00103 
00104 /*
00105  * Set reregistration time. Binary exponential backoff is used on
00106  * reregistrations. Maximum reregistration time is limited with
00107  * NORMAL_REREGISTRATION_TIME. At least half of the lifetime is
00108  * allowed to pass before registration is initiated.
00109  */
00110 static void set_reregistration_time(int total_lifetime)
00111 {
00112         int rt;   /* remaining lifetime */
00113         struct timeval expire_time, now;
00114         struct fa_spi_entry *fa_spi;
00115 
00116         expire_time = timers[TIMER_LIFETIME];
00117 
00118         gettimeofday(&now, NULL);
00119         DEBUG(DEBUG_TIMERS, "set_reregistration_time(%i) - now=%li.%06li\n",
00120               total_lifetime, now.tv_sec, now.tv_usec);
00121         DEBUG(DEBUG_TIMERS, "\tTIMER_LIFETIME: %li.%06li\n",
00122               timers[TIMER_LIFETIME].tv_sec, timers[TIMER_LIFETIME].tv_usec);
00123 
00124         if (config.mn_ha_key_timestamp != 0 &&
00125             config.mn_ha_key_lifetime != 0 &&
00126             expire_time.tv_sec > config.mn_ha_key_timestamp +
00127             config.mn_ha_key_lifetime) {
00128                 expire_time.tv_sec = config.mn_ha_key_timestamp +
00129                         config.mn_ha_key_lifetime;
00130                 expire_time.tv_usec = 0;
00131                 mn.aaa_rekey = 1;
00132 
00133                 DEBUG(DEBUG_TIMERS, "\tMN-HA key lifetime overriding at "
00134                       "%li\n", expire_time.tv_sec);
00135         }
00136 
00137         fa_spi = get_fa_spi(0, mn.fa_addr);
00138         if (fa_spi != NULL && fa_spi->created > 0 &&
00139             expire_time.tv_sec > fa_spi->created + fa_spi->lifetime) {
00140                 expire_time.tv_sec = fa_spi->created + fa_spi->lifetime;
00141                 expire_time.tv_usec = 0;
00142                 mn.aaa_rekey = 1;
00143 
00144                 DEBUG(DEBUG_TIMERS, "\tMN-FA key lifetime overriding at "
00145                       "%li\n", expire_time.tv_sec);
00146         }
00147 
00148         rt = sec_passed(&expire_time);
00149 
00150         /* if total lifetime is set ( > 0), set initial reregistration
00151          *  time, else use exponential backoff
00152          */
00153         if (total_lifetime > 0) {
00154                 /* bound to end of the lifetime */
00155                 if (rt > 2*NORMAL_REREGISTRATION_TIME) {
00156                         timers[TIMER_REREG] = expire_time;
00157                         timers[TIMER_REREG].tv_sec -=
00158                                 mn.aaa_rekey ? MN_AAA_REG_TIME :
00159                                 NORMAL_REREGISTRATION_TIME;
00160                 } else {
00161                         struct timeval rereg;
00162 
00163                         now.tv_sec++;
00164 
00165                         rereg = expire_time;
00166                         rereg.tv_sec -= mn.aaa_rekey ? MN_AAA_REG_TIME :
00167                                 total_lifetime / 2;
00168 
00169                         if (cmp_timeval(&rereg, &now) > 0)
00170                                 timers[TIMER_REREG] = rereg;
00171                         else
00172                                 timers[TIMER_REREG] = now;
00173                 }
00174                 if (mn.current_adv == NULL) {
00175                         LOG2(LOG_ALERT, "set_registration_time - current_adv "
00176                              "== NULL\n");
00177                         mn.HA_reg_retry_time = MIN_REGISTRATION_TIME;
00178                 } else {
00179                         DEBUG(DEBUG_TIMERS, "FA[%s] reg_retry_time = %i\n",
00180                               inet_ntoa(mn.current_adv->addr),
00181                               MIN_REGISTRATION_TIME);
00182                         mn.current_adv->reg_retry_time = MIN_REGISTRATION_TIME;
00183                 }
00184         } else {
00185                 if (mn.current_adv == NULL) {
00186                         LOG2(LOG_ALERT, "set_registration_time - current_adv "
00187                              "== NULL\n");
00188                         if (mn.HA_reg_retry_time == 0)
00189                                 mn.HA_reg_retry_time = MIN_REGISTRATION_TIME;
00190                         else
00191                                 mn.HA_reg_retry_time *= 2;
00192                         timers[TIMER_REREG].tv_sec += mn.HA_reg_retry_time;
00193                 } else {
00194 #ifndef NO_PRIO_DEGRADE
00195                         /* degrade FA priority */
00196                         degrade_current_fa_priority();
00197 #endif /* NO_PRIO_DEGRADE */
00198 
00199                         DEBUG(DEBUG_TIMERS, "FA[%s] reg_retry_time: %i => ",
00200                               inet_ntoa(mn.current_adv->addr),
00201                               mn.current_adv->reg_retry_time);
00202                         if (mn.current_adv->reg_retry_time == 0)
00203                                 mn.current_adv->reg_retry_time =
00204                                         MIN_REGISTRATION_TIME;
00205                         else
00206                                 mn.current_adv->reg_retry_time *= 2;
00207                         DEBUG(DEBUG_TIMERS, "%i\n",
00208                               mn.current_adv->reg_retry_time);
00209                         timers[TIMER_REREG].tv_sec +=
00210                                 mn.current_adv->reg_retry_time;
00211                 }
00212         }
00213 }
00214 
00215 
00216 /* Select next timer to timeout and place timeout to *tv.
00217  * Returns non-zero if timeout is valid otherwise 0. */
00218 static int get_next_timeout(struct timeval *tv)
00219 {
00220         struct timeval *t, now;
00221 
00222         t = &timers[TIMER_GEN];
00223 
00224         if (config.wlan_ap_poll_interval > -1 &&
00225             timerisset(&timers[TIMER_WLAN_AP_POLL]) &&
00226             (!timerisset(t) ||
00227              cmp_timeval(&timers[TIMER_WLAN_AP_POLL], t) < 0))
00228                 t = &timers[TIMER_WLAN_AP_POLL];
00229         if (config.solicitation_interval > -1 &&
00230             timerisset(&timers[TIMER_SOLICITATION]) &&
00231             (!timerisset(t) ||
00232              cmp_timeval(&timers[TIMER_SOLICITATION], t) < 0))
00233                 t = &timers[TIMER_SOLICITATION];
00234 
00235         if (!timerisset(t)) return 0;
00236 
00237         /* check if the current agentadv expires before the TIMER_GEN */
00238         if (mn.current_adv && mn.expire_check &&
00239             cmp_timeval(&mn.current_adv->expire, t) < 0) {
00240                 mn.expire_check = 0;
00241                 t = &mn.current_adv->expire;
00242         }
00243 
00244         gettimeofday(&now, NULL);
00245 
00246         if (now.tv_usec > t->tv_usec) {
00247                 tv->tv_sec = t->tv_sec - now.tv_sec - 1;
00248                 tv->tv_usec = 1000000 + t->tv_usec - now.tv_usec;
00249         } else {
00250                 tv->tv_sec = t->tv_sec - now.tv_sec;
00251                 tv->tv_usec = t->tv_usec - now.tv_usec;
00252         }
00253 
00254         if (tv->tv_sec < 0) timerclear(tv);
00255 
00256         return 1;
00257 }
00258 
00259 
00260 /* State change functions
00261  * Same functions are used for entering the for the state first time and
00262  * retrying after timeout. If state is already set, timeout processing is done.
00263  */
00264 
00265 
00266 /* Just listen to agent advertisements and switch to request_tunnel after one
00267  * is heard. */
00268 void passive_find(void)
00269 {
00270         mn.state = MN_PASSIVE_FIND;
00271         DEBUG(DEBUG_STATES, "State: Passive find\n");
00272 }
00273 
00274 
00275 static void send_solicitations(struct mn_data *mn)
00276 {
00277         int i;
00278         struct timeval now;
00279 
00280         gettimeofday(&now, NULL);
00281         for (i = 0; i < MAX_INTERFACES; i++) {
00282                 if (mn->iface[i].s > -1) {
00283                         if ((now.tv_sec < mn->iface[i].last_solicitation.tv_sec
00284                              || !timerisset(&mn->iface[i].last_solicitation) ||
00285                              usec_passed(&mn->iface[i].last_solicitation, &now)
00286                              > MIN_SOLICITATION_DELAY)) {
00287                                 send_agent_solicitation(mn->iface[i].s);
00288                                 mn->iface[i].last_solicitation = now;
00289                         } else {
00290                                 DEBUG(DEBUG_TIMERS, "Too frequent agent "
00291                                       "solicitations (dev=%s) - skipping\n",
00292                                       mn->iface[i].device);
00293                         }
00294                 }
00295         }
00296 }
00297 
00308 void find_agent(int entry)
00309 {
00310         int t, chg;
00311         static int retry_time = 0; /* time in seconds between retries of agent
00312                                     * solicitations */
00313 
00314         DEBUG(DEBUG_INFO, "find_agent(%i)\n", entry);
00315 
00316         mn.tunnel_up = 0;
00317 
00318         if (mn.device_count == 0) {
00319                 passive_find();
00320                 return;
00321         }
00322 
00323         if (mn.tunnel_mode == API_TUNNEL_FULL_HA) {
00324                 DEBUG(DEBUG_INFO,
00325                       "find_agent: trying to register directly to HA\n");
00326                 if (config.ha_ip_addr.s_addr == 0 &&
00327                     config.home_net_addr_plen > -1) {
00328                         /* dynamic HA address resolution */
00329                         mn.fa_addr.s_addr = config.home_net_subnet_bc.s_addr;
00330                 } else
00331                         mn.fa_addr.s_addr = config.ha_ip_addr.s_addr;
00332                 mn.co_addr.s_addr = mn.local_addr.s_addr;
00333                 if (mn.current_adv != NULL) {
00334                         mn.current_adv->in_use = 0;
00335                         mn.current_adv = NULL;
00336                 }
00337                 request_tunnel(STATE_INIT, 0, 0);
00338                 return;
00339         }
00340 
00341         /* try to find the best FA from the previously received agentadvs;
00342          * if a valid entry is found, use it; otherwise send agent
00343          * solicitation */
00344         chg = get_fa(NULL);
00345         if (chg != FA_GET_NO) {
00346                 DEBUG(DEBUG_INFO, "find_agent: found FA from stored agentadv "
00347                       "data - FA=%s, HFA=", inet_ntoa(mn.fa_addr));
00348                 DEBUG(DEBUG_INFO, "%s\n", inet_ntoa(mn.co_addr));
00349                 request_tunnel(STATE_INIT, 0, 0);
00350                 return;
00351         }
00352 
00353         if (entry == STATE_INIT) {
00354                 mn.state = MN_FIND_AGENT;
00355                 retry_time = 0;
00356                 mn.req_lifetime = config.mn_default_tunnel_lifetime;
00357         }
00358 
00359         t = get_solicitation_interval(&retry_time);
00360         if (t == 0) {
00361                 passive_find();
00362                 return;
00363         }
00364 
00365         /* send agent solicitation to all the active interfaces */
00366         send_solicitations(&mn);
00367 
00368         DEBUG(DEBUG_TIMERS, "find_agent - TIMER_GEN: set now+%i sec\n", t);
00369         gettimeofday(&timers[TIMER_GEN], NULL);
00370         timers[TIMER_GEN].tv_sec += t;
00371         add_usecs(&timers[TIMER_GEN],
00372                   get_rand32() % MAX_RANDOM_SOLICITATION_DELAY);
00373 
00374         DEBUG(DEBUG_STATES, "State: Find agent\n");
00375 }
00376 
00377 
00386 void request_tunnel(int entry, int forced, int check_timer)
00387 {
00388         int retry_time;
00389 
00390         DEBUG(DEBUG_INFO, "request_tunnel(%i, %i, %i)\n", entry, forced,
00391               check_timer);
00392 
00393         if (mn.current_adv == NULL) {
00394                 retry_time = mn.HA_reg_retry_time;
00395                 DEBUG(DEBUG_INFO, "No current agent advertisement " 
00396                       "when requesting tunnel (direct tunnel to HA?)\n");
00397         } else
00398                 retry_time = mn.current_adv->reg_retry_time;
00399 
00400         if (check_timer && retry_time > 1) {
00401                 struct timeval now;
00402                 gettimeofday(&now, NULL);
00403                 if (timerisset(&timers[TIMER_GEN]) &&
00404                     cmp_timeval(&now, &timers[TIMER_GEN]) < 0) {
00405                         DEBUG(DEBUG_TIMERS, "request_tunnel: TIMER_GEN not "
00406                               "yet reached\n");
00407                         return;
00408                 }
00409         }
00410 
00411         if (config.enable_fa_decapsulation && mn.current_adv != NULL)
00412                 add_fa_host_route(mn.current_adv->ifname, mn.agentadv,
00413                                   mn.current_adv->ifindex, mn.fa_addr);
00414 
00415         if (entry == STATE_INIT) {
00416                 mn.state = MN_REQUEST_TUNNEL;
00417                 if (!forced)
00418                         mn.tunnel_up = 0;
00419 
00420                 /* if last registration was sent less than a second ago,
00421                    wait a second before sending the request */
00422                 if (usec_passed(&mn.last_reg_send_time, NULL) <
00423                     MIN_REGISTRATION_DELAY) {
00424                         DEBUG(DEBUG_INFO, "Too frequent registration request "
00425                               "- delaying\n");
00426                         DEBUG(DEBUG_TIMERS, "request_tunnel: TIMER_GEN: set "
00427                               "now+1 sec (too freq.)\n");
00428                         gettimeofday(&timers[TIMER_GEN], NULL);
00429                         timers[TIMER_GEN].tv_sec++;
00430                         return;
00431                 }
00432         } else if (retry_time > MAX_REGISTRATION_TIME) {
00433                 /* STATE_TIMEOUT */
00434                 if (config.use_hadisc) {
00435                         DEBUG(DEBUG_INFO, "HA does not reply - try to discover"
00436                               " another HA\n");
00437                         mn.info_str = "restarting HA discovery";
00438                         config.ha_ip_addr.s_addr = 0;
00439                         if (mn.current_adv != NULL)
00440                                 mn.current_adv->reg_retry_time =
00441                                         MIN_REGISTRATION_TIME;
00442                         else
00443                                 mn.HA_reg_retry_time =
00444                                         MIN_REGISTRATION_TIME;
00445                 } else {
00446                         /* give up, switch to find agent */
00447                         if (forced) {
00448                                 DEBUG(DEBUG_INFO,
00449                                       "Could not confirm tunnel.\n");
00450                                 reply_waiting_api(API_FAILED, NULL, 0);
00451                         } else {
00452                                 DEBUG(DEBUG_INFO, "Could not register.\n");
00453                         }
00454                         find_agent(STATE_INIT);
00455                         return;
00456                 }
00457         } else if (mn.current_adv != NULL) {
00458                 /* STATE_TIMEOUT */
00459 #ifndef NO_PRIO_DEGRADE
00460                 /* degrade the FA priority */
00461                 degrade_current_fa_priority();
00462 #endif /* NO_PRIO_DEGRADE */
00463                 DEBUG(DEBUG_TIMERS, "FA[%s] reg_retry_time: %i => ",
00464                       inet_ntoa(mn.current_adv->addr),
00465                       mn.current_adv->reg_retry_time);
00466                 if (mn.current_adv->reg_retry_time == 0)
00467                         mn.current_adv->reg_retry_time = MIN_REGISTRATION_TIME;
00468                 else
00469                         mn.current_adv->reg_retry_time *= 2;
00470                 DEBUG(DEBUG_TIMERS, "%i\n", mn.current_adv->reg_retry_time);
00471         } else {
00472                 if (mn.HA_reg_retry_time == 0)
00473                         mn.HA_reg_retry_time = MIN_REGISTRATION_TIME;
00474                 else
00475                         mn.HA_reg_retry_time *= 2;
00476         }
00477 
00478         if (send_registration(forced ? REG_REREG : REG_CONNECT) < 0) {
00479                 DEBUG(DEBUG_INFO, "Registration failed for this FA - trying to"
00480                       " find a new one\n");
00481                 mn.warn_str = "Registration failed for this FA, trying to find"
00482                         " a new one";
00483                 find_agent(STATE_INIT);
00484                 return;
00485         }
00486 
00487         gettimeofday(&timers[TIMER_GEN], NULL);
00488         if (mn.current_adv != NULL) {
00489                 if (mn.current_adv->reg_retry_time < MIN_REGISTRATION_TIME)
00490                         mn.current_adv->reg_retry_time = MIN_REGISTRATION_TIME;
00491                 retry_time = mn.current_adv->reg_retry_time;
00492         } else {
00493                 if (mn.HA_reg_retry_time < MIN_REGISTRATION_TIME)
00494                         mn.HA_reg_retry_time = MIN_REGISTRATION_TIME;
00495                 retry_time = mn.HA_reg_retry_time;
00496         }
00497         DEBUG(DEBUG_TIMERS, "request_tunnel - TIMER_GEN: set now+%i sec\n",
00498               retry_time);
00499         timers[TIMER_GEN].tv_sec += retry_time;
00500 
00501         DEBUG(DEBUG_STATES, "State: Request tunnel%s\n",
00502               forced ? " (forced)" : "");
00503 }
00504 
00505 
00506 /* Enter connected state.
00507  * Paramters:
00508  *   type:
00509  *     CON_HA   : connection was approved by HA
00510  *     CON_FA   : connection was approved by FA
00511  *   lifetime: lifetime received in reply
00512  */
00513 void connected(int type, __u16 lifetime)
00514 {
00515         DEBUG(DEBUG_INFO, "connected(%i, %i)\n", type, lifetime);
00516         ASSERT(lifetime > 0);
00517 
00518         if (mn.current_adv != NULL) {
00519                 if (mn.current_adv->addr.s_addr != mn.fa_addr.s_addr) {
00520                         DEBUG(DEBUG_INFO, "fa_addr=%s != ",
00521                               inet_ntoa(mn.fa_addr));
00522                         DEBUG(DEBUG_INFO, "current_adv->addr=%s\n",
00523                               inet_ntoa(mn.current_adv->addr));
00524                 }
00525                 mn.current_adv->in_use = 1;
00526                 /* This FA works, so don't degrade priority: */
00527                 mn.current_adv->prio_degrade_percent = 0; 
00528         } else {
00529                 LOG2(LOG_WARNING, "connected - current_adv == NULL\n");
00530                 mn.warn_str = "connected - current_adv == NULL";
00531         }
00532 
00533         /* HA MUST NOT use larger lifetime and the FAs cannot change the
00534          * requested lifetime - force the lifetime to be at maximum the
00535          * configured time */
00536         if (lifetime > config.mn_default_tunnel_lifetime) {
00537                 LOG2(LOG_WARNING, "Lifetime in the reply (%i sec) larger than "
00538                      "expected (%i sec) - lowering it\n", lifetime,
00539                      config.mn_default_tunnel_lifetime);
00540                 mn.warn_str = "lifetime in the reply larger than expected";
00541                 lifetime = config.mn_default_tunnel_lifetime;
00542         }
00543 
00544         if (config.enable_fa_decapsulation &&
00545             mn.fa_addr.s_addr != mn.tunnel_addr.s_addr &&
00546             mn.tunnel_addr.s_addr != 0 &&
00547             mn.current_adv != NULL)
00548                 remove_fa_host_routes(0);
00549 
00550         /* if tunnel endpoint has changed, or tunnel is down, create tunnel to
00551          * FA */
00552         if (mn.fa_addr.s_addr != mn.tunnel_addr.s_addr || !real_tunnel_up) {
00553                 if (real_tunnel_up) {
00554                         DEBUG(DEBUG_STATES, "Restart tunneling\n");
00555                         restart_tunneling();
00556                 } else {
00557                         DEBUG(DEBUG_STATES, "Start tunneling\n");
00558                         start_tunneling();
00559                 }
00560         }
00561 
00562         /* set lifetime timer */
00563         timers[TIMER_LIFETIME].tv_sec = timers[TIMER_REQUEST].tv_sec +
00564                 lifetime;
00565         timers[TIMER_LIFETIME].tv_usec = timers[TIMER_REQUEST].tv_usec;
00566 
00567           /* If connection was approved by HA,
00568            * reset timer for reregistering the tunnel */
00569         if (type == CON_HA) {
00570                 set_reregistration_time(lifetime);
00571         }
00572         if (mn.state != MN_CONNECTED && type == CON_HA) {
00573                 LOG2(LOG_INFO, "Connection established.\n");
00574                 mn.info_str = "connection established";
00575         }
00576 
00577         DEBUG(DEBUG_TIMERS, "setting TIMER_GEN = TIMER_REREG %li.%06li (in %li"
00578               " sec)\n",
00579               timers[TIMER_REREG].tv_sec, timers[TIMER_REREG].tv_usec,
00580               timers[TIMER_REREG].tv_sec - time(NULL));
00581         timers[TIMER_GEN] = timers[TIMER_REREG];
00582         mn.state = MN_CONNECTED;
00583         mn.tunnel_up = 1;
00584         DEBUG(DEBUG_STATES, "State: Connected\n");
00585 }
00586 
00587 
00588 /* Send registration request and set timer */
00589 static void reregister(void)
00590 {
00591         struct timeval now;
00592 
00593         DEBUG(DEBUG_INFO, "Reregistering..\n");
00594 
00595         /* if tunnel has expired, switch to find agent */
00596         gettimeofday(&now, NULL);
00597         if (cmp_timeval(&timers[TIMER_LIFETIME], &now) <= 0) {
00598                 DEBUG(DEBUG_INFO, "Binding expired - trying to find another "
00599                       "FA and re-establish binding\n");
00600                 mn_remove_dynamic_home_addr();
00601                 
00602                 /* make sure that closest FA won't take next reg_req
00603                  * as locupd. */
00604                 if (mn.session_key != NULL) free(mn.session_key);
00605                 mn.session_key = NULL;
00606                 mn.session_key_len = 0;
00607                 find_agent(STATE_INIT);
00608                 return;
00609         }
00610 
00611         if (send_registration(REG_REREG) < 0) {
00612                 mn.warn_str = "Registration failed, trying to find another FA";
00613                 DEBUG(DEBUG_INFO,
00614                       "Registration failed - trying to find another FA\n");
00615                 if (mn.session_key != NULL) free(mn.session_key);
00616                 mn.session_key = NULL;
00617                 mn.session_key_len = 0;
00618                 find_agent(STATE_INIT);
00619                 return;
00620         }
00621 
00622         set_reregistration_time(0);
00623 
00624         if (cmp_timeval(&timers[TIMER_REREG], &timers[TIMER_LIFETIME]) < 0) {
00625                 DEBUG(DEBUG_TIMERS, "setting TIMER_GEN = TIMER_REREG %li.%06li"
00626                       " (in %li sec)\n", timers[TIMER_REREG].tv_sec,
00627                       timers[TIMER_REREG].tv_usec,
00628                       timers[TIMER_REREG].tv_sec - time(NULL));
00629                 timers[TIMER_GEN] = timers[TIMER_REREG];
00630         } else {
00631                 DEBUG(DEBUG_TIMERS, "setting TIMER_GEN = TIMER_LIFETIME "
00632                       "%li.%06li (in %li sec)\n",
00633                       timers[TIMER_LIFETIME].tv_sec,
00634                       timers[TIMER_LIFETIME].tv_usec,
00635                       timers[TIMER_REREG].tv_sec - time(NULL));
00636                 timers[TIMER_GEN] = timers[TIMER_LIFETIME];
00637         }
00638 
00639 }
00640 
00641 
00642 /* Stop tunneling and send deregistering message to the home agent.
00643  * We'll advance to next state when reply arrives. If the message is lost, it
00644  * will be resent after an interval.
00645  * Parameters:
00646  *  entry - STATE_INIT to move to this state
00647  *          STATE_TIMEOUT to indicate timeout in this state
00648  */
00649 void close_for_home(int entry)
00650 {
00651         int retry_time;
00652 
00653         DEBUG(DEBUG_INFO, "close_for_home(%i)\n", entry);
00654 
00655         if (mn.current_adv == NULL) {
00656                 LOG2(LOG_ALERT, "close_for_home - current_adv == NULL\n");
00657         }
00658         if (entry == STATE_INIT) {
00659                 mn.state = MN_CLOSE_FOR_HOME;
00660                 if (real_tunnel_up)
00661                         stop_tunneling();
00662                 else if (config.shared_secret_len < 0 ||
00663                          config.mn_home_ip_addr.s_addr == 0) {
00664                         DEBUG(DEBUG_INFO,
00665                               "close_for_home - not registered; going directly"
00666                               " to home\n");
00667                         at_home();
00668                         return;
00669                 } else {
00670                         DEBUG(DEBUG_INFO,
00671                               "close_for_home - not registered, but trying to "
00672                               "deregister possible old bindings at HA\n");
00673                         if (mn.co_addr.s_addr == 0)
00674                                 mn.co_addr.s_addr = mn.local_addr.s_addr;
00675                 }
00676                 if (mn.current_adv != NULL) {
00677                         DEBUG(DEBUG_TIMERS, "FA[%s] reg_retry_time: "
00678                               "%i => %i (close_for_home)\n",
00679                               inet_ntoa(mn.current_adv->addr),
00680                               mn.current_adv->reg_retry_time,
00681                               MIN_REGISTRATION_TIME);
00682                         mn.current_adv->reg_retry_time = MIN_REGISTRATION_TIME;
00683                 } else
00684                         mn.HA_reg_retry_time = MIN_REGISTRATION_TIME;
00685 
00686                 /* drop the previous session key so that locupd to FA with the
00687                  * old binding goes to the HA */
00688                 if (mn.session_key != NULL)
00689                         free(mn.session_key);
00690                 mn.session_key = NULL;
00691                 mn.session_key_len = 0;
00692         } else if (mn.current_adv == NULL ||
00693                    mn.current_adv->reg_retry_time >= MAX_REGISTRATION_TIME) {
00694                 DEBUG(DEBUG_MESSAGES,
00695                       "Could not get reply from HA - assuming deregistration "
00696                       "worked\n");
00697                 at_home();
00698                 return;
00699         } else if (mn.current_adv != NULL) {
00700                 DEBUG(DEBUG_TIMERS, "FA[%s] reg_retry_time: %i => ",
00701                       inet_ntoa(mn.current_adv->addr),
00702                       mn.current_adv->reg_retry_time);
00703                 if (mn.current_adv->reg_retry_time == 0)
00704                         mn.current_adv->reg_retry_time = 1;
00705                 else
00706                         mn.current_adv->reg_retry_time *= 2;
00707                 DEBUG(DEBUG_TIMERS, "%i\n", mn.current_adv->reg_retry_time);
00708         }
00709 
00710         send_gratuitous_arp(config.ha_ip_addr, config.mn_home_ip_addr);
00711 
00712         /* send deregistration message to HA */
00713         mn.fa_addr = config.ha_ip_addr;
00714         send_registration(REG_DISC);
00715 
00716         /* at least full retry time should be waited */
00717         gettimeofday(&timers[TIMER_GEN], NULL);
00718         retry_time = mn.current_adv ? mn.current_adv->reg_retry_time :
00719                 mn.HA_reg_retry_time;
00720         DEBUG(DEBUG_TIMERS, "close_for_home - TIMER_GEN: set now+%i sec\n",
00721               retry_time);
00722         timers[TIMER_GEN].tv_sec += retry_time;
00723 
00724         DEBUG(DEBUG_STATES, "State: Close for home\n");
00725 }
00726 
00727 
00728 /* We have successfully deregistered from HA and wait for IP address change
00729  * signal to start tunneling again. */
00730 void at_home(void)
00731 {
00732         DEBUG(DEBUG_INFO, "at_home()\n");
00733         send_gratuitous_arp(config.ha_ip_addr, config.mn_home_ip_addr);
00734         mn.state = MN_AT_HOME;
00735         DEBUG(DEBUG_STATES, "State: At home\n");
00736         DEBUG(DEBUG_TIMERS, "Clearing TIMER_GEN\n");
00737         timerclear(&timers[TIMER_GEN]);
00738         mn_remove_dynamic_home_addr();
00739 }
00740 
00741 
00742 /* We are disconnected from tunneling system and nothing is done until
00743  * connection is asked. */
00744 void disconnect(void)
00745 {
00746         DEBUG(DEBUG_INFO, "disconnect()\n");
00747 
00748         mn.cur_route_info.known = 0;
00749 
00750         /* if we are connected, we'd better throw out a
00751          * deregistration message */
00752         if (mn.state == MN_CONNECTED) {
00753                 send_registration(REG_DISC);
00754                 DEBUG(DEBUG_MESSAGES, "Deregistration message sent\n");
00755         }
00756         if (real_tunnel_up) stop_tunneling();
00757 
00758         /* free session key */
00759         if (mn.session_key) {
00760                 free(mn.session_key);
00761                 mn.session_key = NULL;
00762                 mn.session_key_len = 0;
00763         }
00764 
00765         DEBUG(DEBUG_TIMERS, "Clearing TIMER_GEN\n");
00766         timerclear(&timers[TIMER_GEN]);
00767         mn.state = MN_DISCONNECTED;
00768         DEBUG(DEBUG_STATES, "State: Disconnected\n");
00769         syslog(LOG_INFO, "Disconnected.");
00770         mn_remove_dynamic_home_addr();
00771 }
00772 
00773 
00774 /* handle reregistration when the not supported request option can be fixed */
00775 static void reinitiate_state(void)
00776 {
00777         DEBUG(DEBUG_INFO, "reinitiate_state()\n");
00778 
00779         if (mn.current_adv == NULL) {
00780                 DEBUG(DEBUG_INFO, "reinitiate_state - current_adv == NULL\n");
00781                 mn.HA_reg_retry_time = MIN_REGISTRATION_TIME;
00782         } else {
00783                 DEBUG(DEBUG_TIMERS, "FA[%s] reg_retry_time: "
00784                       "%i => %i (reinitiate_state)\n",
00785                       inet_ntoa(mn.current_adv->addr),
00786                       mn.current_adv->reg_retry_time,
00787                       MIN_REGISTRATION_TIME);
00788                 mn.current_adv->reg_retry_time = MIN_REGISTRATION_TIME;
00789         }
00790         switch (mn.state) {
00791         case MN_REQUEST_TUNNEL:
00792                 request_tunnel(STATE_INIT, 0, 0);
00793                 break;
00794         case MN_CONNECTED:
00795                 reregister();
00796                 break;
00797         default:
00798                 break;
00799         }
00800 }
00801 
00802 
00803 static int check_sol_reply(struct node *node, void *data)
00804 {
00805         struct agentadv_data *adv;
00806         struct timeval *tv;
00807         
00808         adv = (struct agentadv_data *) node;
00809         tv = (struct timeval *) data;
00810 
00811         if (timerisset(tv) && cmp_timeval(&adv->last, tv) < 0 &&
00812             usec_passed(&adv->last, tv) > MAX_AGENTSOL_REPLY_WAIT) {
00813                 DEBUG(DEBUG_INFO, "  timediff=%u\n",
00814                       usec_passed(&adv->last, tv));
00815                 DEBUG(DEBUG_INFO, "No reply from MA (addr=%s) to "
00816                       "agent solicitation within %i usec",
00817                       inet_ntoa(adv->addr), MAX_AGENTSOL_REPLY_WAIT);
00818                 adv->prio_degrade_percent += SOLICITATION_PRIO_DEGRADE;
00819                 if (adv->prio_degrade_percent > 100)
00820                         adv->prio_degrade_percent = 100;
00821                 DEBUG(DEBUG_INFO, " - prio to %i\n",
00822                       adv->prio_degrade_percent);
00823         }
00824 
00825         return TRUE;
00826 }
00827 
00828 
00829 static void handle_timeout(void)
00830 {
00831         struct timeval tv;
00832 
00833         DEBUG(DEBUG_TIMERS, "Timeout\n");
00834         gettimeofday(&tv, NULL);
00835 
00836 #ifdef WITH_WIRELESS
00837         if (config.wlan_ap_poll_interval > -1 &&
00838             timerisset(&timers[TIMER_WLAN_AP_POLL]) &&
00839             cmp_timeval(&tv, &timers[TIMER_WLAN_AP_POLL]) >= 0) {
00840                 DEBUG(DEBUG_TIMERS, "\tTIMER_WLAN_AP_POLL\n");
00841                 /* poll AP addresses and send agentsol if handoff has
00842                  * occured (do this for each interface supporting wireless
00843                  * extensions) */
00844                 monitor_poll_ap_addresses(&mn);
00845                 timers[TIMER_WLAN_AP_POLL].tv_sec = tv.tv_sec;
00846                 timers[TIMER_WLAN_AP_POLL].tv_usec = tv.tv_usec;
00847                 add_usecs(&timers[TIMER_WLAN_AP_POLL],
00848                           config.wlan_ap_poll_interval);
00849         }
00850 #endif /* WITH_WIRELESS */
00851 
00852         if (config.solicitation_interval > -1 &&
00853             timerisset(&timers[TIMER_SOLICITATION]) &&
00854             cmp_timeval(&tv, &timers[TIMER_SOLICITATION]) >= 0) {
00855                 DEBUG(DEBUG_TIMERS, "\tTIMER_SOLICITATION\n");
00856                 /* check whether some FAs did not reply previous solicitation
00857                  */
00858                 hashtable_iterator(mn.agentadv, check_sol_reply,
00859                                    &mn.last_scheduled_solicitation);
00860                 /* send agentsol to all interfaces */
00861                 send_solicitations(&mn);
00862                 timers[TIMER_SOLICITATION].tv_sec = tv.tv_sec;
00863                 timers[TIMER_SOLICITATION].tv_usec = tv.tv_usec;
00864                 add_usecs(&timers[TIMER_SOLICITATION],
00865                           config.solicitation_interval +
00866                           get_rand32() % MAX_RANDOM_SOLICITATION_DELAY);
00867                 mn.last_scheduled_solicitation = tv;
00868         }
00869 
00870 
00871         if (!timerisset(&timers[TIMER_GEN])) {
00872                 DEBUG(DEBUG_TIMERS, "\tTIMER_GEN is not set\n");
00873                 return;
00874         }
00875 
00876         if (cmp_timeval(&tv, &timers[TIMER_GEN]) < 0) {
00877                 DEBUG(DEBUG_TIMERS, "\tTIMER_GEN not yet reached - ignoring "
00878                       "timeout\n");
00879                 return;
00880         }
00881 
00882         /* disable timer */
00883         DEBUG(DEBUG_TIMERS, "\tdisabling TIMER_GEN\n");
00884         timerclear(&timers[TIMER_GEN]);
00885 
00886         switch (mn.state) {
00887         case MN_DISCONNECTED:
00888         case MN_AT_HOME:
00889                 break;
00890         case MN_CLOSE_FOR_HOME:
00891                 close_for_home(STATE_TIMEOUT);
00892                 break;
00893         case MN_FIND_AGENT:
00894                 find_agent(STATE_TIMEOUT);
00895                 break;
00896         case MN_PASSIVE_FIND:
00897                 break;
00898         case MN_REQUEST_TUNNEL:
00899                 request_tunnel(STATE_TIMEOUT, 0, 0);
00900                 break;
00901         case MN_CONNECTED:
00902                 reregister();
00903                 break;
00904         default:
00905                 break;
00906         }
00907 }
00908 
00909 
00910 int main_vanha(int argc, char *argv[])
00911 {
00912         int n, i;
00913         fd_set set;
00914         struct timeval tv;
00915 
00916         memset(&mn, 0, sizeof(mn));
00917         mn.info_str = "initialization in progress";
00918 
00919         program_name = parse_long_options(argc, argv, "mobile node",
00920                                              PACKAGE, VERSION, dynamics_usage);
00921 
00922         mn_parse_command_line(argc, argv);
00923 
00924         if (!mn_init()) {
00925                 fprintf(stderr, "Initialization failed.\n");
00926                 exit(0);
00927         }
00928 
00929         if (mn.opt_connect) {
00930                 /* try to connect to a FA if MN is using FA decapsulation (i.e.
00931                  * its own home IP addr also in the foreign network) or if the
00932                  * home address is not assigned to a local interface with MN
00933                  * decapsulation */
00934                 mn.info_str = "trying to connect";
00935                 if (config.enable_fa_decapsulation || is_coloc_addr_foreign())
00936                 {
00937                         mn.tunnel_mode = API_TUNNEL_FULL;
00938                         find_agent(STATE_INIT);
00939                 } else at_home();
00940         }
00941 
00942         /* MN main loop */
00943         while (mn.state != MN_STOP) {
00944                 check_old_tunnel_expiration();
00945 
00946                 FD_ZERO(&set);
00947                 FD_SET(mn.registration_socket, &set);
00948                 for (i = 0; i < MAX_INTERFACES; i++) {
00949                         if (mn.iface[i].s_adv > -1)
00950                                 FD_SET(mn.iface[i].s_adv, &set);
00951                 }
00952                 if (mn.api_rw_socket > -1)
00953                         FD_SET(mn.api_rw_socket, &set);
00954                 if (mn.api_ro_socket > -1)
00955                         FD_SET(mn.api_ro_socket, &set);
00956 #ifdef INCLUDE_IPAY
00957                 FD_SET(mn.ipay_sock, &set);
00958                 FD_SET(mn.ipay_sock_fa, &set);
00959 #endif
00960                 if (mn.rtnetlink_socket > -1)
00961                         FD_SET(mn.rtnetlink_socket, &set);
00962 
00963                 if (get_next_timeout(&tv))
00964                         n = select(FD_SETSIZE, &set, NULL, NULL, &tv);
00965                 else n = select(FD_SETSIZE, &set, NULL, NULL, NULL);
00966                 if (n == 0) {
00967                         handle_timeout();
00968                         continue;
00969                 } else if (n == -1) {
00970                         switch (errno) {
00971                         case EINTR:
00972                                 break;
00973                         default:
00974                                 LOG2(LOG_ERR, "main - select: %s\n",
00975                                      strerror(errno));
00976                                 /* this used to exit dynmnd with
00977                                  * mn.state = MN_STOP;
00978                                  * but this might be a temporary problem, so
00979                                  * try agains; use a small delay to prevent
00980                                  * hogging all the CPU in case of select()
00981                                  * returning error all the time */
00982                                 sleep(1);
00983                         }
00984                         continue;
00985                 }
00986 
00987                 if (FD_ISSET(mn.registration_socket, &set) &&
00988                     handle_registration(mn.registration_socket)) {
00989                         /* try to reregister */
00990                         reinitiate_state();
00991                 }
00992 
00993                 for (i = 0; i < MAX_INTERFACES; i++) {
00994                         if (mn.iface[i].s_adv > -1 &&
00995                             FD_ISSET(mn.iface[i].s_adv, &set))
00996                                 handle_icmp(&mn.iface[i]);
00997                 }
00998 
00999                 if (mn.rtnetlink_socket > -1 &&
01000                     FD_ISSET(mn.rtnetlink_socket, &set)) {
01001                         int res = dyn_ip_monitor_get(
01002                                 mn.rtnetlink_socket,
01003                                 (config.enforce_routes &&
01004                                  mn.state != MN_DISCONNECTED) ?
01005                                 &mn.cur_route_info : NULL);
01006                         if (res == 1 || res == 2)
01007                                 check_interfaces(mn.iface, MAX_INTERFACES);
01008                 }
01009 
01010                 if (mn.api_rw_socket > -1 && FD_ISSET(mn.api_rw_socket, &set))
01011                         handle_api(mn.api_rw_socket, 1);
01012 
01013                 if (mn.api_ro_socket > -1 && FD_ISSET(mn.api_ro_socket, &set))
01014                         handle_api(mn.api_ro_socket, 0);
01015 
01016 #ifdef INCLUDE_IPAY
01017                 if (FD_ISSET(mn.ipay_sock, &set))
01018                         handle_ipay(mn.ipay_sock);
01019                 if (FD_ISSET(mn.ipay_sock_fa, &set))
01020                         handle_ipay(mn.ipay_sock_fa);
01021 #endif
01022 
01023                 /* check expired agent advs. If current FA's agent
01024                    adv. has expired move to FIND_AGENT state */
01025                 if (check_expired_agent_advs())
01026                         find_agent(STATE_INIT);
01027         }
01028 
01029         clean_up(0);
01030         return 0;
01031 }

Generated on Tue Jan 15 08:50:43 2008 for Virtual foreign agent generator version 0.1 by  doxygen 1.5.1