📄 mn_agentadv.c
字号:
/* $Id: mn_agentadv.c,v 1.76 2001/09/29 18:42:07 jm Exp $ * Mobile Node agentadv module * * Dynamic hierarchial IP tunnel * Copyright (C) 1998-2001, Dynamics group * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See README and COPYING for * more details. */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdlib.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <string.h>#include <assert.h>#include <errno.h>#include <stddef.h>#include <features.h> /* for the glibc version number */#include <unistd.h>#ifdef DYN_TARGET_LINUX#include <net/if_arp.h>#ifndef __GLIBC__/* get struct iphdr */#include <linux/ip.h>#endif#endif#include "hashtable.h"#include "debug.h"#include "fileio.h"#include "proxyarp.h"#ifdef WITH_WIRELESS#include "monitor.h"#endif#include "dyn_ip.h"#include "agentapi.h"#include "util.h"#include "mn_agentadv.h"#include "mn_handler.h"#include "mn.h"/* fa decision .. */static struct agentadv_data *max_adv;static int max_priority;static struct timeval max_adv_time;extern struct mn_data mn; extern struct mn_config config;extern struct timeval timers[TIMER_COUNT];extern int real_tunnel_up; /* from mn_tunnel */int adv_ok_fa(struct agentadv_data *adv){ int opts; if (mn.force_fa_addr.s_addr != 0 && mn.force_fa_addr.s_addr != adv->addr.s_addr) return 0; if (adv->adv.ext == NULL) return 0; opts = ntohs(adv->adv.ext->opts); if ((opts & AGENT_ADV_BUSY) || !(opts & AGENT_ADV_FOREIGN_AGENT)) return 0; if (config.tunneling_mode == TUNMODE_REVERSE && !(opts & AGENT_ADV_BIDIR_TUNNELING)) return 0; if (config.tunneling_mode == TUNMODE_TRIANGLE && adv->adv.own_ext != NULL && !(adv->adv.own_ext->opts & AGENT_ADV_OWN_TRIANGLE_TUNNELING)) return 0; return 1;}static int addr_cmp(void *key, struct node *cmprd){ struct agentadv_data *entry = (struct agentadv_data *) cmprd; struct agentadv_key *akey = (struct agentadv_key *) key; if (akey->addr.s_addr == entry->addr.s_addr && (akey->ifindex == 0 || akey->ifindex == entry->ifindex)) return TRUE; return FALSE;}static int addr_hash(void *key, const int tablesize){ unsigned char *addr; struct agentadv_key *akey = (struct agentadv_key *) key; addr = (unsigned char *) &akey->addr; return (int) (addr[0] ^ addr[1] ^ addr[2] ^ addr[3]);}/** * adv_fetch: * @adv_hash: hash of agent advertisements * @addr: address of agent * @ifindex: 0 to accept any interface, or index of a given * interface * * fetch an agent advertisement from the @adv_hash. * addr: the source IP address of the agent advertisment packet * * Returns: the matching advertisement */struct agentadv_data *adv_fetch(struct hashtable *adv_hash, struct in_addr *addr, int ifindex){ struct agentadv_data *adv; struct agentadv_key key; key.addr.s_addr = addr->s_addr; key.ifindex = ifindex; adv = (struct agentadv_data *) hashtable_fetch(adv_hash, addr_hash, &key, addr_cmp); return (adv);}static int current_agent_expired;/* remove hashtable entry, if the current time (data as struct timeval *) is * NULL (forced cleaning) or if the entry has expired */int clean_agentadv(struct node *node, void *data){ struct agentadv_data *adv; struct timeval *tval; struct event_FA dat; adv = (struct agentadv_data *) node; tval = (struct timeval *) data; if (tval != NULL && cmp_timeval(tval, &adv->expire) < 0) return TRUE; /* not expired */ if (tval != NULL && adv->in_use) { /* in use and removal not forced */ current_agent_expired = TRUE; return TRUE; } DEBUG(DEBUG_AGENTADV, "clean_agentadv: removing %s\n", inet_ntoa(adv->addr)); /* call handlers registered for FA_ADV_EXPIRE event */ dat.adv = adv; dat.hash = mn.agentadv; handler_call_all(FA_ADV_EXPIRE, &dat); /* remove the possible ARP entries etc. */ if (adv->arpentry == 1 && arp_del_permanent_item(adv->addr, adv->ifname) < 0) { if (device_up(adv->ifindex)) { LOG2(LOG_WARNING, "arp_del_permanent_item(%s, %s) failed\n", inet_ntoa(adv->addr), adv->ifname); } else { DEBUG(DEBUG_INFO, "arp_del_permanent_item(%s, %s) " "failed (device down)\n", inet_ntoa(adv->addr), adv->ifname); } } /* remove the possible host route to FA */ if (adv->routeentry == 1) { DEBUG(DEBUG_INFO, "Removing FA route (%s,%s)\n", inet_ntoa(adv->addr), adv->ifname); if (dyn_ip_route_del(adv->addr, adv->ifname) != 0) DEBUG(DEBUG_INFO, "FA route removing failed\n"); } if (mn.current_adv == adv) { DEBUG(DEBUG_AGENTADV, "clean_agentadv: removed current_adv\n"); mn.current_adv = NULL; } hashtable_remove(node); free(adv); return TRUE;}static void handle_home_adv(struct agentadv_data *adv){ struct in_addr addr; DEBUG(DEBUG_AGENTADV, "Home advertisement\n"); if (config.priv_ha_ip_addr.s_addr != 0) addr = config.priv_ha_ip_addr; else addr = config.ha_ip_addr; if (addr.s_addr != adv->addr.s_addr) { struct node *iter; int found = 0; for (iter = list_get_first(&config.alt_ha_ip_addrs); iter != NULL; iter = list_get_next(iter)) { struct alt_ha_entry *alt = (struct alt_ha_entry *) iter; if (alt->addr.s_addr == adv->addr.s_addr) { found = 1; break; } } if (!found) { DEBUG(DEBUG_AGENTADV, "\tnot our HA\n"); return; } } if (config.ha_nai_len > 0) { struct fa_nai_ext *fa_nai = (struct fa_nai_ext *) adv->adv.fa_nai; if (fa_nai == NULL) { DEBUG(DEBUG_AGENTADV, "\tno NAI extension in agent adv" " - ignoring packet\n"); return; } if (config.ha_nai_len != GET_NAI_LEN(fa_nai)) { DEBUG(DEBUG_AGENTADV, "\tNAI length mismatch - " "ignoring packet\n"); return; } if (memcmp(config.ha_nai, MSG_NAI_DATA(fa_nai), config.ha_nai_len) != 0) { DEBUG(DEBUG_AGENTADV, "\tNAI mismatch - ignoring " "packet\n"); return; } } if (mn.current_adv != NULL && mn.current_adv->in_use) mn.current_adv->in_use = 0; mn.current_adv = adv; mn.current_adv->in_use = 1; mn.cur_route_info.ifindex = mn.cur_route_info.ifindex_net = adv->ifindex; memcpy(mn.cur_route_info.ifname, adv->ifname, IFNAMSIZ); memcpy(mn.cur_route_info.ifname_net, adv->ifname, IFNAMSIZ); mn.cur_route_info.known = 1; mn.cur_route_info.via.s_addr = config.home_net_gateway.s_addr; adv->adv_type = MN_ADV_TYPE_OWN_HA; DEBUG(DEBUG_AGENTADV, "\tfrom our own HA - MN is at home\n"); if (mn.state == MN_FIND_AGENT || mn.state == MN_PASSIVE_FIND || mn.state == MN_REQUEST_TUNNEL || mn.state == MN_CONNECTED) { /* FIX: if the co-loc. COA was used, the address of the * interface must be set to the home network settings. * Currently it is assumed that some external program * handles the IP addresses if co-loc. COA is used. */ DEBUG(DEBUG_INFO, "Deregistering due to the heard " "own HA agent advertisement\n"); close_for_home(STATE_INIT); }}/* hashtable iterator for update_fa_decision() * searches the entry with largest priority */static int find_fa_with_priority(struct node *node, void *data){ struct agentadv_data *adv; adv = (struct agentadv_data *) node; if (monitor_check_policy(NEWEST_ADV_BIT)) { /* special case for Newest-ADV policy: just select the latest * received advertisement */ if (!timerisset(&max_adv_time) || cmp_timeval(&max_adv_time, &adv->last) < 0) { max_adv_time = adv->last; max_adv = adv; } return TRUE; } adv->priority_degraded = adv->priority; DEBUG(DEBUG_HANDLERS, "%s priority %i", inet_ntoa(adv->addr), adv->priority_degraded); /* degrade priority by degrade percent */ if (adv->prio_degrade_percent > 0 && adv->priority_degraded > 0) { adv->priority_degraded = (int) (adv->priority_degraded * ((100.0 - adv->prio_degrade_percent) / 100.0)); /* do not totally deny this FA */ if (adv->priority_degraded == 0) adv->priority_degraded = 1; DEBUG(DEBUG_HANDLERS, " => %i (-%i%%)", adv->priority_degraded, adv->prio_degrade_percent); } DEBUG(DEBUG_HANDLERS, "\n"); if (adv->priority_degraded > max_priority && !adv->reg_failed && (adv_ok_fa(adv) || adv == mn.current_adv)) { max_priority = adv->priority_degraded; max_adv = adv; } return TRUE;}/* Called after FA_GET handlers */static int update_fa_decision(struct agentadv_data *adv){ int same_prio; struct timeval now; gettimeofday(&now, NULL); /* (A) * if we are at home and the HA's agentadv has not expired, do not try * to change the FA */ if ((mn.state == MN_AT_HOME || mn.state == MN_CLOSE_FOR_HOME) && mn.current_adv != NULL && mn.current_adv->addr.s_addr == config.ha_ip_addr.s_addr && mn.current_adv->adv.ext != NULL && ntohs(mn.current_adv->adv.ext->opts) & AGENT_ADV_HOME_AGENT && cmp_timeval(&mn.current_adv->expire, &now) >= 0 && !monitor_check_policy(NEWEST_ADV_BIT)) { DEBUG(DEBUG_AGENTADV, "HA agentadv still valid - staying at home\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -