00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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
00037 #include "fixed_fd_zero.h"
00038 #ifdef INCLUDE_IPAY
00039 #include "mn_ipay.h"
00040 #endif
00041
00042 extern int real_tunnel_up;
00043
00044 struct mn_data mn;
00045 struct mn_config config;
00046
00047 struct timeval timers[TIMER_COUNT];
00048 char *program_name;
00049
00050
00051
00052
00053
00054
00055
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
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
00106
00107
00108
00109
00110 static void set_reregistration_time(int total_lifetime)
00111 {
00112 int rt;
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
00151
00152
00153 if (total_lifetime > 0) {
00154
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
00196 degrade_current_fa_priority();
00197 #endif
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
00217
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
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
00261
00262
00263
00264
00265
00266
00267
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;
00312
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
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
00342
00343
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
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
00421
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
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
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
00459 #ifndef NO_PRIO_DEGRADE
00460
00461 degrade_current_fa_priority();
00462 #endif
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
00507
00508
00509
00510
00511
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
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
00534
00535
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
00551
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
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
00568
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
00589 static void reregister(void)
00590 {
00591 struct timeval now;
00592
00593 DEBUG(DEBUG_INFO, "Reregistering..\n");
00594
00595
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
00603
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
00643
00644
00645
00646
00647
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
00687
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
00713 mn.fa_addr = config.ha_ip_addr;
00714 send_registration(REG_DISC);
00715
00716
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
00729
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
00743
00744 void disconnect(void)
00745 {
00746 DEBUG(DEBUG_INFO, "disconnect()\n");
00747
00748 mn.cur_route_info.known = 0;
00749
00750
00751
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
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
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
00842
00843
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
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
00857
00858 hashtable_iterator(mn.agentadv, check_sol_reply,
00859 &mn.last_scheduled_solicitation);
00860
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
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
00931
00932
00933
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
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
00977
00978
00979
00980
00981
00982 sleep(1);
00983 }
00984 continue;
00985 }
00986
00987 if (FD_ISSET(mn.registration_socket, &set) &&
00988 handle_registration(mn.registration_socket)) {
00989
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
01024
01025 if (check_expired_agent_advs())
01026 find_agent(STATE_INIT);
01027 }
01028
01029 clean_up(0);
01030 return 0;
01031 }