⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mn.c

📁 mobile ip 在linux下的一种实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: mn.c,v 1.239 2001/10/20 14:44:19 jm Exp $ * Mobile Node - state machine and main loop * * 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 <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <string.h>#include <stdio.h>#include <arpa/inet.h>#include <stdlib.h>#include <time.h>#include <assert.h>#include <errno.h>#include <unistd.h>#include "agentapi.h"#include "debug.h"#include "util.h"#include "dyn_ip.h"#include "mn.h"#ifndef DYN_TARGET_WINDOWS#include "monitor.h"#endif /* DYN_TARGET_WINDOWS */#include "fixed_fd_zero.h"#ifdef INCLUDE_IPAY#include "mn_ipay.h"#endifextern int real_tunnel_up; /* from mn_tunnel */struct mn_data mn;struct mn_config config; /* configuration information *//* Timers containing ending time for the timer */struct timeval timers[TIMER_COUNT];char *program_name;/* * Determine the timeout value in seconds for a solicitation request. * Parameters: *  counter - pointer to variable holding information, *            how many requests have been sent. * Returns: timeout in seconds or zero when it's time to go passive mode. */static int get_solicitation_interval(int *counter){	static int intervals[] = SOLICITATION_INTERVALS;	int t;	ASSERT(counter != NULL);	ASSERT(sizeof(intervals) > 0);	if (*counter < 0) *counter = 0;	if (*counter >= sizeof(intervals) / sizeof(int))		t = 0;	else t = intervals[*counter];	(*counter)++;	return t;}/* * Due to the unsuccessful registration to the FA, degrade its priority. */int degrade_current_fa_priority(void){	if (mn.current_adv == NULL)		return 1;	if (mn.current_adv->prio_degrade_percent == 0) {		mn.current_adv->prio_degrade_percent = 			DEFAULT_PRIO_DEGRADE_INITIAL;	} else {		mn.current_adv->prio_degrade_percent *= 			DEFAULT_PRIO_DEGRADE_FACTOR;	}	if (mn.current_adv->prio_degrade_percent > 100) {		mn.current_adv->prio_degrade_percent = 100;	}	DEBUG(DEBUG_INFO, "degrade_current_fa_priority: %d\n",	      mn.current_adv->prio_degrade_percent);		return 0;}/* * Set reregistration time. Binary exponential backoff is used on * reregistrations. Maximum reregistration time is limited with * NORMAL_REREGISTRATION_TIME. At least half of the lifetime is * allowed to pass before registration is initiated. */static void set_reregistration_time(int total_lifetime){	int rt;   /* remaining lifetime */	struct timeval expire_time, now;	struct fa_spi_entry *fa_spi;	expire_time = timers[TIMER_LIFETIME];	gettimeofday(&now, NULL);	DEBUG(DEBUG_TIMERS, "set_reregistration_time(%i) - now=%li.%06li\n",	      total_lifetime, now.tv_sec, now.tv_usec);	DEBUG(DEBUG_TIMERS, "\tTIMER_LIFETIME: %li.%06li\n",	      timers[TIMER_LIFETIME].tv_sec, timers[TIMER_LIFETIME].tv_usec);	if (config.mn_ha_key_timestamp != 0 &&	    config.mn_ha_key_lifetime != 0 &&	    expire_time.tv_sec > config.mn_ha_key_timestamp +	    config.mn_ha_key_lifetime) {		expire_time.tv_sec = config.mn_ha_key_timestamp +			config.mn_ha_key_lifetime;		expire_time.tv_usec = 0;		mn.aaa_rekey = 1;		DEBUG(DEBUG_TIMERS, "\tMN-HA key lifetime overriding at "		      "%li\n", expire_time.tv_sec);	}	fa_spi = get_fa_spi(0, mn.fa_addr);	if (fa_spi != NULL && fa_spi->created > 0 &&	    expire_time.tv_sec > fa_spi->created + fa_spi->lifetime) {		expire_time.tv_sec = fa_spi->created + fa_spi->lifetime;		expire_time.tv_usec = 0;		mn.aaa_rekey = 1;		DEBUG(DEBUG_TIMERS, "\tMN-FA key lifetime overriding at "		      "%li\n", expire_time.tv_sec);	}	rt = sec_passed(&expire_time);	/* if total lifetime is set ( > 0), set initial reregistration	 *  time, else use exponential backoff	 */	if (total_lifetime > 0) {		/* bound to end of the lifetime */		if (rt > 2*NORMAL_REREGISTRATION_TIME) {			timers[TIMER_REREG] = expire_time;			timers[TIMER_REREG].tv_sec -=				mn.aaa_rekey ? MN_AAA_REG_TIME :				NORMAL_REREGISTRATION_TIME;		} else {			struct timeval rereg;			now.tv_sec++;			rereg = expire_time;			rereg.tv_sec -= mn.aaa_rekey ? MN_AAA_REG_TIME :				total_lifetime / 2;			if (cmp_timeval(&rereg, &now) > 0)				timers[TIMER_REREG] = rereg;			else				timers[TIMER_REREG] = now;		}		if (mn.current_adv == NULL) {			LOG2(LOG_ALERT, "set_registration_time - current_adv "			     "== NULL\n");			mn.HA_reg_retry_time = MIN_REGISTRATION_TIME;		} else {			DEBUG(DEBUG_TIMERS, "FA[%s] reg_retry_time = %i\n",			      inet_ntoa(mn.current_adv->addr),			      MIN_REGISTRATION_TIME);			mn.current_adv->reg_retry_time = MIN_REGISTRATION_TIME;		}	} else {		if (mn.current_adv == NULL) {			LOG2(LOG_ALERT, "set_registration_time - current_adv "			     "== NULL\n");			if (mn.HA_reg_retry_time == 0)				mn.HA_reg_retry_time = MIN_REGISTRATION_TIME;			else				mn.HA_reg_retry_time *= 2;			timers[TIMER_REREG].tv_sec += mn.HA_reg_retry_time;		} else {#ifndef NO_PRIO_DEGRADE			/* degrade FA priority */			degrade_current_fa_priority();#endif /* NO_PRIO_DEGRADE */			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 =					MIN_REGISTRATION_TIME;			else				mn.current_adv->reg_retry_time *= 2;			DEBUG(DEBUG_TIMERS, "%i\n",			      mn.current_adv->reg_retry_time);			timers[TIMER_REREG].tv_sec +=				mn.current_adv->reg_retry_time;		}	}}/* Select next timer to timeout and place timeout to *tv. * Returns non-zero if timeout is valid otherwise 0. */static int get_next_timeout(struct timeval *tv){	struct timeval *t, now;	t = &timers[TIMER_GEN];	if (config.wlan_ap_poll_interval > -1 &&	    timerisset(&timers[TIMER_WLAN_AP_POLL]) &&	    (!timerisset(t) ||	     cmp_timeval(&timers[TIMER_WLAN_AP_POLL], t) < 0))		t = &timers[TIMER_WLAN_AP_POLL];	if (config.solicitation_interval > -1 &&	    timerisset(&timers[TIMER_SOLICITATION]) &&	    (!timerisset(t) ||	     cmp_timeval(&timers[TIMER_SOLICITATION], t) < 0))		t = &timers[TIMER_SOLICITATION];	if (!timerisset(t)) return 0;	/* check if the current agentadv expires before the TIMER_GEN */	if (mn.current_adv && mn.expire_check &&	    cmp_timeval(&mn.current_adv->expire, t) < 0) {		mn.expire_check = 0;		t = &mn.current_adv->expire;	}	gettimeofday(&now, NULL);	if (now.tv_usec > t->tv_usec) {		tv->tv_sec = t->tv_sec - now.tv_sec - 1;		tv->tv_usec = 1000000 + t->tv_usec - now.tv_usec;	} else {		tv->tv_sec = t->tv_sec - now.tv_sec;		tv->tv_usec = t->tv_usec - now.tv_usec;	}	if (tv->tv_sec < 0) timerclear(tv);	return 1;}/* State change functions * Same functions are used for entering the for the state first time and * retrying after timeout. If state is already set, timeout processing is done. *//* Just listen to agent advertisements and switch to request_tunnel after one * is heard. */void passive_find(void){        mn.state = MN_PASSIVE_FIND;        DEBUG(DEBUG_STATES, "State: Passive find\n");}static void send_solicitations(struct mn_data *mn){	int i;	struct timeval now;	gettimeofday(&now, NULL);	for (i = 0; i < MAX_INTERFACES; i++) {		if (mn->iface[i].s > -1) {			if ((now.tv_sec < mn->iface[i].last_solicitation.tv_sec			     || !timerisset(&mn->iface[i].last_solicitation) ||			     usec_passed(&mn->iface[i].last_solicitation, &now)			     > MIN_SOLICITATION_DELAY)) {				send_agent_solicitation(mn->iface[i].s);				mn->iface[i].last_solicitation = now;			} else {				DEBUG(DEBUG_TIMERS, "Too frequent agent "				      "solicitations (dev=%s) - skipping\n",				      mn->iface[i].device);			}		}	}}/** * find_agent: * @entry - STATE_INIT to move to this state *          STATE_TIMEOUT to indicate timeout in this state, *          ie. we haven't received an agent adv to our last sent *          solicitation * *  Enter find agent state * */void find_agent(int entry){	int t, chg;	static int retry_time = 0; /* time in seconds between retries of agent				    * solicitations */	DEBUG(DEBUG_INFO, "find_agent(%i)\n", entry);	mn.tunnel_up = 0;	if (mn.device_count == 0) {		passive_find();		return;	}	if (mn.tunnel_mode == API_TUNNEL_FULL_HA) {		DEBUG(DEBUG_INFO,		      "find_agent: trying to register directly to HA\n");		if (config.ha_ip_addr.s_addr == 0 &&		    config.home_net_addr_plen > -1) {			/* dynamic HA address resolution */			mn.fa_addr.s_addr = config.home_net_subnet_bc.s_addr;		} else			mn.fa_addr.s_addr = config.ha_ip_addr.s_addr;		mn.co_addr.s_addr = mn.local_addr.s_addr;		if (mn.current_adv != NULL) {			mn.current_adv->in_use = 0;			mn.current_adv = NULL;		}		request_tunnel(STATE_INIT, 0, 0);		return;	}	/* try to find the best FA from the previously received agentadvs;	 * if a valid entry is found, use it; otherwise send agent	 * solicitation */	chg = get_fa(NULL);	if (chg != FA_GET_NO) {		DEBUG(DEBUG_INFO, "find_agent: found FA from stored agentadv "		      "data - FA=%s, HFA=", inet_ntoa(mn.fa_addr));		DEBUG(DEBUG_INFO, "%s\n", inet_ntoa(mn.co_addr));		request_tunnel(STATE_INIT, 0, 0);		return;	}	if (entry == STATE_INIT) {                mn.state = MN_FIND_AGENT;                retry_time = 0;		mn.req_lifetime = config.mn_default_tunnel_lifetime;	}	t = get_solicitation_interval(&retry_time);	if (t == 0) {		passive_find();		return;	}	/* send agent solicitation to all the active interfaces */	send_solicitations(&mn);	DEBUG(DEBUG_TIMERS, "find_agent - TIMER_GEN: set now+%i sec\n", t);	gettimeofday(&timers[TIMER_GEN], NULL);	timers[TIMER_GEN].tv_sec += t;	add_usecs(&timers[TIMER_GEN],		  get_rand32() % MAX_RANDOM_SOLICITATION_DELAY);	DEBUG(DEBUG_STATES, "State: Find agent\n");}/** * rqeuest_tunnel: * @entry: STATE_INIT to move to this state, *         STATE_TIMEOUT to indicate timeout in this state, *         i.e. no reply for last request within retry time * * Enter request tunnel state */void request_tunnel(int entry, int forced, int check_timer){	int retry_time;	DEBUG(DEBUG_INFO, "request_tunnel(%i, %i, %i)\n", entry, forced,	      check_timer);	if (mn.current_adv == NULL) {		retry_time = mn.HA_reg_retry_time;		DEBUG(DEBUG_INFO, "No current agent advertisement " 		      "when requesting tunnel (direct tunnel to HA?)\n");	} else		retry_time = mn.current_adv->reg_retry_time;	if (check_timer && retry_time > 1) {		struct timeval now;		gettimeofday(&now, NULL);		if (timerisset(&timers[TIMER_GEN]) &&		    cmp_timeval(&now, &timers[TIMER_GEN]) < 0) {			DEBUG(DEBUG_TIMERS, "request_tunnel: TIMER_GEN not "			      "yet reached\n");			return;		}	}	if (config.enable_fa_decapsulation && mn.current_adv != NULL)		add_fa_host_route(mn.current_adv->ifname, mn.agentadv,				  mn.current_adv->ifindex, mn.fa_addr);        if (entry == STATE_INIT) {                mn.state = MN_REQUEST_TUNNEL;		if (!forced)			mn.tunnel_up = 0;		/* if last registration was sent less than a second ago,		   wait a second before sending the request */		if (usec_passed(&mn.last_reg_send_time, NULL) <		    MIN_REGISTRATION_DELAY) {			DEBUG(DEBUG_INFO, "Too frequent registration request "			      "- delaying\n");			DEBUG(DEBUG_TIMERS, "request_tunnel: TIMER_GEN: set "			      "now+1 sec (too freq.)\n");			gettimeofday(&timers[TIMER_GEN], NULL);			timers[TIMER_GEN].tv_sec++;			return;		}        } else if (retry_time > MAX_REGISTRATION_TIME) {		/* STATE_TIMEOUT */		if (config.use_hadisc) {			DEBUG(DEBUG_INFO, "HA does not reply - try to discover"			      " another HA\n");			mn.info_str = "restarting HA discovery";			config.ha_ip_addr.s_addr = 0;			if (mn.current_adv != NULL)				mn.current_adv->reg_retry_time =					MIN_REGISTRATION_TIME;			else				mn.HA_reg_retry_time =					MIN_REGISTRATION_TIME;		} else {			/* give up, switch to find agent */			if (forced) {				DEBUG(DEBUG_INFO,				      "Could not confirm tunnel.\n");				reply_waiting_api(API_FAILED, NULL, 0);			} else {				DEBUG(DEBUG_INFO, "Could not register.\n");			}			find_agent(STATE_INIT);			return;		}        } else if (mn.current_adv != NULL) {		/* STATE_TIMEOUT */#ifndef NO_PRIO_DEGRADE		/* degrade the FA priority */		degrade_current_fa_priority();#endif /* NO_PRIO_DEGRADE */		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 = MIN_REGISTRATION_TIME;		else			mn.current_adv->reg_retry_time *= 2;		DEBUG(DEBUG_TIMERS, "%i\n", mn.current_adv->reg_retry_time);	} else {		if (mn.HA_reg_retry_time == 0)			mn.HA_reg_retry_time = MIN_REGISTRATION_TIME;		else			mn.HA_reg_retry_time *= 2;	}	if (send_registration(forced ? REG_REREG : REG_CONNECT) < 0) {		DEBUG(DEBUG_INFO, "Registration failed for this FA - trying to"		      " find a new one\n");		mn.warn_str = "Registration failed for this FA, trying to find"			" a new one";		find_agent(STATE_INIT);		return;	}        gettimeofday(&timers[TIMER_GEN], NULL);	if (mn.current_adv != NULL) {		if (mn.current_adv->reg_retry_time < MIN_REGISTRATION_TIME)			mn.current_adv->reg_retry_time = MIN_REGISTRATION_TIME;		retry_time = mn.current_adv->reg_retry_time;	} else {		if (mn.HA_reg_retry_time < MIN_REGISTRATION_TIME)			mn.HA_reg_retry_time = MIN_REGISTRATION_TIME;		retry_time = mn.HA_reg_retry_time;	}	DEBUG(DEBUG_TIMERS, "request_tunnel - TIMER_GEN: set now+%i sec\n",	      retry_time);	timers[TIMER_GEN].tv_sec += retry_time;        DEBUG(DEBUG_STATES, "State: Request tunnel%s\n",	      forced ? " (forced)" : "");}/* Enter connected state. * Paramters: *   type: *     CON_HA   : connection was approved by HA *     CON_FA   : connection was approved by FA *   lifetime: lifetime received in reply */void connected(int type, __u16 lifetime){	DEBUG(DEBUG_INFO, "connected(%i, %i)\n", type, lifetime);	ASSERT(lifetime > 0);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -