📄 mn_agentadv.c
字号:
return FA_GET_NO; } /* if we are using direct connection to the HA, do not try to change * the FA */ if (mn.tunnel_mode == API_TUNNEL_FULL_HA) { DEBUG(DEBUG_AGENTADV, "Direct connection to the HA - ignoring " "FA agent advertisement\n"); return FA_GET_NO; } /* Get FA with max priority */ max_adv = NULL; max_priority = 0; timerclear(&max_adv_time); if (mn.agentadv == NULL) { DEBUG(DEBUG_AGENTADV, "update_fa_decision: mn.agentadv == " "NULL\n"); return FA_GET_NO; } hashtable_iterator(mn.agentadv, find_fa_with_priority, NULL); if (max_adv == NULL) { DEBUG(DEBUG_AGENTADV, "update_fa_decision: Can't find FA!\n"); return FA_GET_NO; } if (mn.current_adv != NULL) { DEBUG(DEBUG_AGENTADV, "CURRENT: %s ", inet_ntoa(mn.current_adv->addr)); DEBUG(DEBUG_AGENTADV, "MAX: %s\n", inet_ntoa(max_adv->addr)); } /* (B) * If same priority, don't change */ /* FIX: How to compare two LFAs. How can we know that they are same * JM-FIX: use FA NAI */ if (mn.current_adv != NULL) same_prio = mn.current_adv->priority_degraded == max_priority; else same_prio = FALSE; /* skip priority check if Newest-ADV policy is used */ if (monitor_check_policy(NEWEST_ADV_BIT)) same_prio = FALSE; if (mn.current_adv != NULL && (same_prio || mn.current_adv->addr.s_addr == max_adv->addr.s_addr)) { return FA_GET_SAME; /* no change if same priority or SAME FA */ } /* Change FA. First update the FA information */ mn.fa_addr.s_addr = max_adv->addr.s_addr; memcpy(&mn.co_addr, (max_adv->adv.ext) + 1, sizeof(struct in_addr)); mn.req_lifetime = ntohs(max_adv->adv.ext->reg_lifetime); if (mn.current_adv != NULL) mn.current_adv->in_use = 0; mn.current_adv = max_adv; memcpy(&mn.fa_dynamics_ext, &max_adv->adv.own_ext, sizeof(struct agent_adv_dynamics)); gettimeofday(&timers[TIMER_ADV], NULL); timers[TIMER_ADV].tv_sec += ntohs(max_adv->adv.radv->lifetime); return FA_GET_CHANGED;}/* Get a FA * Returns: * 0 = FA not found or HA agentadv still valid => do not try to register * 1 = new FA found * 2 = FA found, but it is the same as the current FA */int get_fa(struct agentadv_data *adv){ struct event_FA data; data.adv = adv; data.hash = mn.agentadv; handler_call_all(FA_GET, &data); return update_fa_decision(adv);}static void handle_fa_adv(struct agentadv_data *adv){ struct in_addr _fa_addr, _highest_fa_addr; int chg = 0; struct event_FA data; UNALIGNED_(&_fa_addr.s_addr, &adv->adv.ip->saddr); memcpy(&_highest_fa_addr, adv->adv.ext + 1, sizeof(struct in_addr)); DEBUG(DEBUG_AGENTADV, "FA advertisement - fa_addr=%s, ", inet_ntoa(_fa_addr)); DEBUG(DEBUG_AGENTADV, "highest_fa_addr=%s\n", inet_ntoa(_highest_fa_addr)); /* Call all handlers for this event: FA_ADV_RECEIVE */ data.adv = adv; data.hash = mn.agentadv; handler_call_all(FA_ADV_RECEIVE, &data); if (mn.state == MN_CONNECTED && ntohs(adv->adv.ext->seq) < 256 && adv->last_heard_seqn >= ntohs(adv->adv.ext->seq)) { adv->last_heard_seqn = ntohs(adv->adv.ext->seq); DEBUG(DEBUG_INFO, "FA rebooted - trying to reregister\n"); request_tunnel(STATE_INIT, 0, 0); return; } /* update sequence number */ adv->last_heard_seqn = ntohs(adv->adv.ext->seq); switch (mn.state) { case MN_DISCONNECTED: break; case MN_AT_HOME: case MN_CLOSE_FOR_HOME: /* try to register to an FA if the HA's agentadv expires */ if (mn.current_adv == NULL || mn.current_adv->adv_type != MN_ADV_TYPE_OWN_HA || adv->adv_type != MN_ADV_TYPE_FA) break; if (cmp_timeval(&adv->last, &mn.current_adv->expire) < 0 && !monitor_check_policy(NEWEST_ADV_BIT)) break; DEBUG(DEBUG_INFO, "HA agentadv expired - trying to use FA (IP=%s)\n", inet_ntoa(adv->addr)); /* continue to next case statement.. */ case MN_FIND_AGENT: case MN_PASSIVE_FIND: case MN_REQUEST_TUNNEL: /* FIX: if the real tunnel is not yet up and the MN gets a * flood of agentadvs from different FAs, there might not be * enough time for the reply to arrive and MN might try to * register to yet another FA.. */ chg = get_fa(adv); if (chg == FA_GET_CHANGED || (chg == FA_GET_SAME && (real_tunnel_up == 0 || mn.state != MN_REQUEST_TUNNEL))) request_tunnel(STATE_INIT, 0, 1); break; case MN_CONNECTED: chg = get_fa(adv); /* start requesting the tunnel if the current FA's seq# * indicates that the FA has rebooted or if the FA has been * changed */ if (chg == FA_GET_CHANGED) { request_tunnel(STATE_INIT, 0, 1); } break; default: break; }}/* check_expired_agent_advs: * * Remove old agent advertisement datas from the memory * * Returns: 1 if current agent has expired, else 0 */int check_expired_agent_advs(void){ static time_t prev_check = 0; struct timeval now; struct timeval tmp; gettimeofday(&now, NULL); if (prev_check <= now.tv_sec && now.tv_sec < prev_check + ADV_CLEANUP_FREQ) return 0; prev_check = now.tv_sec; current_agent_expired = FALSE; tmp.tv_sec = now.tv_sec - ADV_EXTRA_TIME; tmp.tv_usec = now.tv_usec; DEBUG(DEBUG_AGENTADV, "\tchecking for expired agentadv data\n"); hashtable_iterator(mn.agentadv, clean_agentadv, &tmp); if (current_agent_expired) { DEBUG(DEBUG_AGENTADV, "Current agent's adv. expired - try to " "find new FA\n"); return 1; } return 0;}/* handle incoming agent advertisement * Returns: * 0 - no extra processing needed * 1 - current agent's advertisement has expired */int handle_icmp(struct interface_data *iface){ char buf[MAX_ADV_MSG]; struct adv_extensions ext; struct agentadv_key key; struct agentadv_data *adv; int res; /* return, if message was not for us */ res = handle_icmp_adv(iface->s_adv, buf, MAX_ADV_MSG, &ext); if (res == -1) { /* network is down - rescan interfaces */ check_interfaces(mn.iface, MAX_INTERFACES); } if (res != 1) return 0; UNALIGNED_(&key.addr.s_addr, &ext.ip->saddr);#ifndef MN_FA_FORCE_AFTER_AGENTADV_UPDATE if (mn.force_fa_addr.s_addr != 0 && mn.force_fa_addr.s_addr != key.addr.s_addr) { DEBUG(DEBUG_AGENTADV, "handle_icmp: force_fa set to %s - ignoring this FA(1)", inet_ntoa(mn.force_fa_addr)); DEBUG(DEBUG_AGENTADV, " (%s)\n", inet_ntoa(key.addr)); return 0; }#endif /* MN_FA_FORCE_AFTER_AGENTADV_UPDATE */ key.ifindex = iface->index; if (ntohs(ext.ext->reg_lifetime) < MIN_ALLOWED_LIFETIME) { DEBUG(DEBUG_AGENTADV, "handle_icmp: too small lifetime advertised (%d) " "- ignoring this FA (%s)\n", ntohs(ext.ext->reg_lifetime), inet_ntoa(key.addr)); return 0; } /* save the last agentadv */ adv = (struct agentadv_data *) hashtable_fetch(mn.agentadv, addr_hash, &key, addr_cmp); if (adv == NULL) { /* we have no previous information on this mobility agent */ adv = (struct agentadv_data *) malloc(sizeof(struct agentadv_data)); if (adv == NULL) { DEBUG(DEBUG_AGENTADV, "handle_icmp: no memory for agentadv data\n"); return 0; } DEBUG(DEBUG_AGENTADV, "Added new agentadv entry for %s\n", inet_ntoa(key.addr)); memset(adv, 0, sizeof(struct agentadv_data)); list_init_node(&adv->node); UNALIGNED_(&adv->addr.s_addr, &ext.ip->saddr); adv->counter = 1; adv->prio_degrade_percent = 0; /* don't degrade new FAs! */ if (!hashtable_add(mn.agentadv, addr_hash, &key.addr, &adv->node)) { DEBUG(DEBUG_AGENTADV, "handle_icmp: hashtable_add failed\n"); free(adv); return 0; } } else { /* updating information for previously heard mobility agent */ DEBUG(DEBUG_AGENTADV, "Used old agentadv entry for %s\n", inet_ntoa(key.addr)); adv->counter++; /* Let FA become slowly "available" again */ if (adv->prio_degrade_percent > 0) adv->prio_degrade_percent = (int) (adv->prio_degrade_percent* DEFAULT_PRIO_DEGRADE_DEGRADE); /* remove the reg_failed flag if the adv. opts has changed */ if (adv->reg_failed && ext.ext->opts != adv->adv.ext->opts) { DEBUG(DEBUG_AGENTADV, "Reseting reg_failed for this FA\n"); adv->reg_failed = 0; } } adv->ifindex = iface->index; dynamics_strlcpy(adv->ifname, iface->device, sizeof(adv->ifname)); gettimeofday(&adv->last, NULL); adv->expire.tv_sec = adv->last.tv_sec + ntohs(ext.radv->lifetime) + 1; adv->expire.tv_usec = adv->last.tv_usec; DEBUG(DEBUG_AGENTADV, "\tnow=%li.%li, expire=%li.%li\n", adv->last.tv_sec, adv->last.tv_usec, adv->expire.tv_sec, adv->expire.tv_usec); memcpy(adv->buf, buf, MAX_ADV_MSG); memcpy(&adv->adv, &ext, sizeof(struct adv_extensions)); adv->adv.start = adv->buf; adv->adv.len = ext.len; adv->adv.coaddrs = ext.coaddrs; memcpy(&adv->adv.from, &ext.from, sizeof(ext.from));#define UPDATE_OFFSET(n) adv->adv.n = ext.n ? \(typeof(ext.n)) (((char *) ext.n) - ext.start + adv->adv.start) : NULL#ifndef DYN_TARGET_LINUX UPDATE_OFFSET(eth);#endif UPDATE_OFFSET(ip); UPDATE_OFFSET(radv); UPDATE_OFFSET(ext); UPDATE_OFFSET(prefix); UPDATE_OFFSET(own_ext); UPDATE_OFFSET(pubkey_hash); UPDATE_OFFSET(fa_nai); UPDATE_OFFSET(challenge);#ifdef MN_FA_FORCE_AFTER_AGENTADV_UPDATE if (mn.force_fa_addr.s_addr != 0 && mn.force_fa_addr.s_addr != key.addr.s_addr) { DEBUG(DEBUG_AGENTADV, "handle_icmp: force_fa set to %s - ignoring this FA(2)", inet_ntoa(mn.force_fa_addr)); DEBUG(DEBUG_AGENTADV, " (%s)\n", inet_ntoa(key.addr)); return 0; }#endif /* MN_FA_FORCE_AFTER_AGENTADV_UPDATE */ if (ntohs(ext.ext->opts) & AGENT_ADV_HOME_AGENT) { adv->adv_type = MN_ADV_TYPE_HA; handle_home_adv(adv); } if (ntohs(ext.ext->opts) & AGENT_ADV_FOREIGN_AGENT) { if (adv->adv_type != MN_ADV_TYPE_OWN_HA) adv->adv_type = MN_ADV_TYPE_FA; if (ext.coaddrs <= 0) DEBUG(DEBUG_AGENTADV, "handle_icmp: FA adv with no COAs - ignoring\n"); else handle_fa_adv(adv); } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -