📄 mn.c
字号:
if (mn.current_adv != NULL) { if (mn.current_adv->addr.s_addr != mn.fa_addr.s_addr) { DEBUG(DEBUG_INFO, "fa_addr=%s != ", inet_ntoa(mn.fa_addr)); DEBUG(DEBUG_INFO, "current_adv->addr=%s\n", inet_ntoa(mn.current_adv->addr)); } mn.current_adv->in_use = 1; /* This FA works, so don't degrade priority: */ mn.current_adv->prio_degrade_percent = 0; } else { LOG2(LOG_WARNING, "connected - current_adv == NULL\n"); mn.warn_str = "connected - current_adv == NULL"; } /* HA MUST NOT use larger lifetime and the FAs cannot change the * requested lifetime - force the lifetime to be at maximum the * configured time */ if (lifetime > config.mn_default_tunnel_lifetime) { LOG2(LOG_WARNING, "Lifetime in the reply (%i sec) larger than " "expected (%i sec) - lowering it\n", lifetime, config.mn_default_tunnel_lifetime); mn.warn_str = "lifetime in the reply larger than expected"; lifetime = config.mn_default_tunnel_lifetime; } if (config.enable_fa_decapsulation && mn.fa_addr.s_addr != mn.tunnel_addr.s_addr && mn.tunnel_addr.s_addr != 0 && mn.current_adv != NULL) remove_fa_host_routes(0); /* if tunnel endpoint has changed, or tunnel is down, create tunnel to * FA */ if (mn.fa_addr.s_addr != mn.tunnel_addr.s_addr || !real_tunnel_up) { if (real_tunnel_up) { DEBUG(DEBUG_STATES, "Restart tunneling\n"); restart_tunneling(); } else { DEBUG(DEBUG_STATES, "Start tunneling\n"); start_tunneling(); } } /* set lifetime timer */ timers[TIMER_LIFETIME].tv_sec = timers[TIMER_REQUEST].tv_sec + lifetime; timers[TIMER_LIFETIME].tv_usec = timers[TIMER_REQUEST].tv_usec; /* If connection was approved by HA, * reset timer for reregistering the tunnel */ if (type == CON_HA) { set_reregistration_time(lifetime); } if (mn.state != MN_CONNECTED && type == CON_HA) { LOG2(LOG_INFO, "Connection established.\n"); mn.info_str = "connection established"; } DEBUG(DEBUG_TIMERS, "setting TIMER_GEN = TIMER_REREG %li.%06li (in %li" " sec)\n", timers[TIMER_REREG].tv_sec, timers[TIMER_REREG].tv_usec, timers[TIMER_REREG].tv_sec - time(NULL)); timers[TIMER_GEN] = timers[TIMER_REREG]; mn.state = MN_CONNECTED; mn.tunnel_up = 1; DEBUG(DEBUG_STATES, "State: Connected\n");}/* Send registration request and set timer */static void reregister(void){ struct timeval now; DEBUG(DEBUG_INFO, "Reregistering..\n"); /* if tunnel has expired, switch to find agent */ gettimeofday(&now, NULL); if (cmp_timeval(&timers[TIMER_LIFETIME], &now) <= 0) { DEBUG(DEBUG_INFO, "Binding expired - trying to find another " "FA and re-establish binding\n"); mn_remove_dynamic_home_addr(); /* make sure that closest FA won't take next reg_req * as locupd. */ if (mn.session_key != NULL) free(mn.session_key); mn.session_key = NULL; mn.session_key_len = 0; find_agent(STATE_INIT); return; } if (send_registration(REG_REREG) < 0) { mn.warn_str = "Registration failed, trying to find another FA"; DEBUG(DEBUG_INFO, "Registration failed - trying to find another FA\n"); if (mn.session_key != NULL) free(mn.session_key); mn.session_key = NULL; mn.session_key_len = 0; find_agent(STATE_INIT); return; } set_reregistration_time(0); if (cmp_timeval(&timers[TIMER_REREG], &timers[TIMER_LIFETIME]) < 0) { DEBUG(DEBUG_TIMERS, "setting TIMER_GEN = TIMER_REREG %li.%06li" " (in %li sec)\n", timers[TIMER_REREG].tv_sec, timers[TIMER_REREG].tv_usec, timers[TIMER_REREG].tv_sec - time(NULL)); timers[TIMER_GEN] = timers[TIMER_REREG]; } else { DEBUG(DEBUG_TIMERS, "setting TIMER_GEN = TIMER_LIFETIME " "%li.%06li (in %li sec)\n", timers[TIMER_LIFETIME].tv_sec, timers[TIMER_LIFETIME].tv_usec, timers[TIMER_REREG].tv_sec - time(NULL)); timers[TIMER_GEN] = timers[TIMER_LIFETIME]; }}/* Stop tunneling and send deregistering message to the home agent. * We'll advance to next state when reply arrives. If the message is lost, it * will be resent after an interval. * Parameters: * entry - STATE_INIT to move to this state * STATE_TIMEOUT to indicate timeout in this state */void close_for_home(int entry){ int retry_time; DEBUG(DEBUG_INFO, "close_for_home(%i)\n", entry); if (mn.current_adv == NULL) { LOG2(LOG_ALERT, "close_for_home - current_adv == NULL\n"); } if (entry == STATE_INIT) { mn.state = MN_CLOSE_FOR_HOME; if (real_tunnel_up) stop_tunneling(); else if (config.shared_secret_len < 0 || config.mn_home_ip_addr.s_addr == 0) { DEBUG(DEBUG_INFO, "close_for_home - not registered; going directly" " to home\n"); at_home(); return; } else { DEBUG(DEBUG_INFO, "close_for_home - not registered, but trying to " "deregister possible old bindings at HA\n"); if (mn.co_addr.s_addr == 0) mn.co_addr.s_addr = mn.local_addr.s_addr; } if (mn.current_adv != NULL) { DEBUG(DEBUG_TIMERS, "FA[%s] reg_retry_time: " "%i => %i (close_for_home)\n", inet_ntoa(mn.current_adv->addr), mn.current_adv->reg_retry_time, MIN_REGISTRATION_TIME); mn.current_adv->reg_retry_time = MIN_REGISTRATION_TIME; } else mn.HA_reg_retry_time = MIN_REGISTRATION_TIME; /* drop the previous session key so that locupd to FA with the * old binding goes to the HA */ if (mn.session_key != NULL) free(mn.session_key); mn.session_key = NULL; mn.session_key_len = 0; } else if (mn.current_adv == NULL || mn.current_adv->reg_retry_time >= MAX_REGISTRATION_TIME) { DEBUG(DEBUG_MESSAGES, "Could not get reply from HA - assuming deregistration " "worked\n"); at_home(); return; } else if (mn.current_adv != NULL) { DEBUG(DEBUG_TIMERS, "FA[%s] reg_retry_time: %i => ", inet_ntoa(mn.current_adv->addr), mn.current_adv->reg_retry_time); if (mn.current_adv->reg_retry_time == 0) mn.current_adv->reg_retry_time = 1; else mn.current_adv->reg_retry_time *= 2; DEBUG(DEBUG_TIMERS, "%i\n", mn.current_adv->reg_retry_time); } send_gratuitous_arp(config.ha_ip_addr, config.mn_home_ip_addr); /* send deregistration message to HA */ mn.fa_addr = config.ha_ip_addr; send_registration(REG_DISC); /* at least full retry time should be waited */ gettimeofday(&timers[TIMER_GEN], NULL); retry_time = mn.current_adv ? mn.current_adv->reg_retry_time : mn.HA_reg_retry_time; DEBUG(DEBUG_TIMERS, "close_for_home - TIMER_GEN: set now+%i sec\n", retry_time); timers[TIMER_GEN].tv_sec += retry_time; DEBUG(DEBUG_STATES, "State: Close for home\n");}/* We have successfully deregistered from HA and wait for IP address change * signal to start tunneling again. */void at_home(void){ DEBUG(DEBUG_INFO, "at_home()\n"); send_gratuitous_arp(config.ha_ip_addr, config.mn_home_ip_addr); mn.state = MN_AT_HOME; DEBUG(DEBUG_STATES, "State: At home\n"); DEBUG(DEBUG_TIMERS, "Clearing TIMER_GEN\n"); timerclear(&timers[TIMER_GEN]); mn_remove_dynamic_home_addr();}/* We are disconnected from tunneling system and nothing is done until * connection is asked. */void disconnect(void){ DEBUG(DEBUG_INFO, "disconnect()\n"); mn.cur_route_info.known = 0; /* if we are connected, we'd better throw out a * deregistration message */ if (mn.state == MN_CONNECTED) { send_registration(REG_DISC); DEBUG(DEBUG_MESSAGES, "Deregistration message sent\n"); } if (real_tunnel_up) stop_tunneling(); /* free session key */ if (mn.session_key) { free(mn.session_key); mn.session_key = NULL; mn.session_key_len = 0; } DEBUG(DEBUG_TIMERS, "Clearing TIMER_GEN\n"); timerclear(&timers[TIMER_GEN]); mn.state = MN_DISCONNECTED; DEBUG(DEBUG_STATES, "State: Disconnected\n"); syslog(LOG_INFO, "Disconnected."); mn_remove_dynamic_home_addr();}/* handle reregistration when the not supported request option can be fixed */static void reinitiate_state(void){ DEBUG(DEBUG_INFO, "reinitiate_state()\n"); if (mn.current_adv == NULL) { DEBUG(DEBUG_INFO, "reinitiate_state - current_adv == NULL\n"); mn.HA_reg_retry_time = MIN_REGISTRATION_TIME; } else { DEBUG(DEBUG_TIMERS, "FA[%s] reg_retry_time: " "%i => %i (reinitiate_state)\n", inet_ntoa(mn.current_adv->addr), mn.current_adv->reg_retry_time, MIN_REGISTRATION_TIME); mn.current_adv->reg_retry_time = MIN_REGISTRATION_TIME; } switch (mn.state) { case MN_REQUEST_TUNNEL: request_tunnel(STATE_INIT, 0, 0); break; case MN_CONNECTED: reregister(); break; default: break; }}static int check_sol_reply(struct node *node, void *data){ struct agentadv_data *adv; struct timeval *tv; adv = (struct agentadv_data *) node; tv = (struct timeval *) data; if (timerisset(tv) && cmp_timeval(&adv->last, tv) < 0 && usec_passed(&adv->last, tv) > MAX_AGENTSOL_REPLY_WAIT) { DEBUG(DEBUG_INFO, " timediff=%u\n", usec_passed(&adv->last, tv)); DEBUG(DEBUG_INFO, "No reply from MA (addr=%s) to " "agent solicitation within %i usec", inet_ntoa(adv->addr), MAX_AGENTSOL_REPLY_WAIT); adv->prio_degrade_percent += SOLICITATION_PRIO_DEGRADE; if (adv->prio_degrade_percent > 100) adv->prio_degrade_percent = 100; DEBUG(DEBUG_INFO, " - prio to %i\n", adv->prio_degrade_percent); } return TRUE;}static void handle_timeout(void){ struct timeval tv; DEBUG(DEBUG_TIMERS, "Timeout\n"); gettimeofday(&tv, NULL);#ifdef WITH_WIRELESS if (config.wlan_ap_poll_interval > -1 && timerisset(&timers[TIMER_WLAN_AP_POLL]) && cmp_timeval(&tv, &timers[TIMER_WLAN_AP_POLL]) >= 0) { DEBUG(DEBUG_TIMERS, "\tTIMER_WLAN_AP_POLL\n"); /* poll AP addresses and send agentsol if handoff has * occured (do this for each interface supporting wireless * extensions) */ monitor_poll_ap_addresses(&mn); timers[TIMER_WLAN_AP_POLL].tv_sec = tv.tv_sec; timers[TIMER_WLAN_AP_POLL].tv_usec = tv.tv_usec; add_usecs(&timers[TIMER_WLAN_AP_POLL], config.wlan_ap_poll_interval); }#endif /* WITH_WIRELESS */ if (config.solicitation_interval > -1 && timerisset(&timers[TIMER_SOLICITATION]) && cmp_timeval(&tv, &timers[TIMER_SOLICITATION]) >= 0) { DEBUG(DEBUG_TIMERS, "\tTIMER_SOLICITATION\n"); /* check whether some FAs did not reply previous solicitation */ hashtable_iterator(mn.agentadv, check_sol_reply, &mn.last_scheduled_solicitation); /* send agentsol to all interfaces */ send_solicitations(&mn); timers[TIMER_SOLICITATION].tv_sec = tv.tv_sec; timers[TIMER_SOLICITATION].tv_usec = tv.tv_usec; add_usecs(&timers[TIMER_SOLICITATION], config.solicitation_interval + get_rand32() % MAX_RANDOM_SOLICITATION_DELAY); mn.last_scheduled_solicitation = tv; } if (!timerisset(&timers[TIMER_GEN])) { DEBUG(DEBUG_TIMERS, "\tTIMER_GEN is not set\n"); return; } if (cmp_timeval(&tv, &timers[TIMER_GEN]) < 0) { DEBUG(DEBUG_TIMERS, "\tTIMER_GEN not yet reached - ignoring " "timeout\n"); return; } /* disable timer */ DEBUG(DEBUG_TIMERS, "\tdisabling TIMER_GEN\n"); timerclear(&timers[TIMER_GEN]); switch (mn.state) { case MN_DISCONNECTED: case MN_AT_HOME: break; case MN_CLOSE_FOR_HOME: close_for_home(STATE_TIMEOUT); break; case MN_FIND_AGENT: find_agent(STATE_TIMEOUT); break; case MN_PASSIVE_FIND: break; case MN_REQUEST_TUNNEL: request_tunnel(STATE_TIMEOUT, 0, 0); break; case MN_CONNECTED: reregister(); break; default: break; }}int main(int argc, char *argv[]){ int n, i; fd_set set; struct timeval tv; memset(&mn, 0, sizeof(mn)); mn.info_str = "initialization in progress"; program_name = parse_long_options(argc, argv, "mobile node", PACKAGE, VERSION, dynamics_usage); mn_parse_command_line(argc, argv); if (!mn_init()) { fprintf(stderr, "Initialization failed.\n"); exit(0); } if (mn.opt_connect) { /* try to connect to a FA if MN is using FA decapsulation (i.e. * its own home IP addr also in the foreign network) or if the * home address is not assigned to a local interface with MN * decapsulation */ mn.info_str = "trying to connect"; if (config.enable_fa_decapsulation || is_coloc_addr_foreign()) { mn.tunnel_mode = API_TUNNEL_FULL; find_agent(STATE_INIT); } else at_home(); } /* MN main loop */ while (mn.state != MN_STOP) { check_old_tunnel_expiration(); FD_ZERO(&set); FD_SET(mn.registration_socket, &set); for (i = 0; i < MAX_INTERFACES; i++) { if (mn.iface[i].s_adv > -1) FD_SET(mn.iface[i].s_adv, &set); } if (mn.api_rw_socket > -1) FD_SET(mn.api_rw_socket, &set); if (mn.api_ro_socket > -1) FD_SET(mn.api_ro_socket, &set);#ifdef INCLUDE_IPAY FD_SET(mn.ipay_sock, &set); FD_SET(mn.ipay_sock_fa, &set);#endif if (mn.rtnetlink_socket > -1) FD_SET(mn.rtnetlink_socket, &set); if (get_next_timeout(&tv)) n = select(FD_SETSIZE, &set, NULL, NULL, &tv); else n = select(FD_SETSIZE, &set, NULL, NULL, NULL); if (n == 0) { handle_timeout(); continue; } else if (n == -1) { switch (errno) { case EINTR: break; default: LOG2(LOG_ERR, "main - select: %s\n", strerror(errno)); /* this used to exit dynmnd with * mn.state = MN_STOP; * but this might be a temporary problem, so * try agains; use a small delay to prevent * hogging all the CPU in case of select() * returning error all the time */ sleep(1); } continue; } if (FD_ISSET(mn.registration_socket, &set) && handle_registration(mn.registration_socket)) { /* try to reregister */ reinitiate_state(); } for (i = 0; i < MAX_INTERFACES; i++) { if (mn.iface[i].s_adv > -1 && FD_ISSET(mn.iface[i].s_adv, &set)) handle_icmp(&mn.iface[i]); } if (mn.rtnetlink_socket > -1 && FD_ISSET(mn.rtnetlink_socket, &set)) { int res = dyn_ip_monitor_get( mn.rtnetlink_socket, (config.enforce_routes && mn.state != MN_DISCONNECTED) ? &mn.cur_route_info : NULL); if (res == 1 || res == 2) check_interfaces(mn.iface, MAX_INTERFACES); } if (mn.api_rw_socket > -1 && FD_ISSET(mn.api_rw_socket, &set)) handle_api(mn.api_rw_socket, 1); if (mn.api_ro_socket > -1 && FD_ISSET(mn.api_ro_socket, &set)) handle_api(mn.api_ro_socket, 0);#ifdef INCLUDE_IPAY if (FD_ISSET(mn.ipay_sock, &set)) handle_ipay(mn.ipay_sock); if (FD_ISSET(mn.ipay_sock_fa, &set)) handle_ipay(mn.ipay_sock_fa);#endif /* check expired agent advs. If current FA's agent adv. has expired move to FIND_AGENT state */ if (check_expired_agent_advs()) find_agent(STATE_INIT); } clean_up(0); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -