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

📄 binding.c

📁 mobile ip 在linux下的一种实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: binding.c,v 1.33 2001/02/17 15:29:55 jm Exp $ * Mobility bindings used in FAs and HAs. * * 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. */#define DEBUG_FLAG 'B'#include "owntypes.h"#include <stdio.h>#include <stdlib.h>#include <stddef.h>#include <time.h>#include <assert.h>#include <sys/types.h>#include <netinet/in.h>#include <sys/socket.h>#include <arpa/inet.h>#include "binding.h"#include "debug.h"/* Home and foreign agents keep track of * registered mobile nodes with mobility bindings. *//* * Bindings have a lifetime. The current time in seconds * since 0:00:00 UTC, January 1, 1970 can be retrieved with the time * system call (see man 2 time). The expiration time for a binding * is set in exp_time. When the current time is equal to or * more than exp_time the binding should be removed. * * Both foreign and home agents need to know where to forward * packets destined for the mobile node; this is indicated by the * lower_addr field. The session key for the tunnel is stored * in the key field. The corresponding security parameter index for * authentication method used is stored in the spi field. */struct bindingtable {	struct hashtable *hashtable;    /* hash table for bindings */	unsigned int hashtablesize;     /* number of entries in hash table */	struct list *shorttimelist;     /* short time list (STL) table */	unsigned int shorttimelistsize; /* amount of entries in STL table */	struct list longtimelist;	/* should be empty all the time */	struct list noexptimelist;	/* entries that do not expire */	unsigned int firstindex;        /* entry to be reported next */	unsigned int currentindex;	/* current time index */};/* defines */#define ASSERT assert#ifndef FALSE#define FALSE 0#endif#ifndef TRUE#define TRUE 1#endif/* Test cases *//*#define BINDING_TEST_CASE_I05*//*TEST CASE I10: MANUALLY*//*#define BINDING_TEST_CASE_I12*//* prototypes */static int binding_hash(void *key, const int tablesize);static int binding_compare(void *key, struct node *cmprd);static int binding_getexpired_alreadyexpired(struct bindingtable *table,					     int idx, int *checklongtimelist,					     int *listempty);static int binding_getexpired_advance(struct bindingtable *table, int advance,				      int idx, int *checklongtimelist);static int binding_getexpired_checkmaxadvancetime(struct bindingtable *table,						  int left, int *advance);static void binding_check_longtimelist(struct bindingtable *table,				       const int advance);/* "Ixx" are test case IDs to help in the design of the test module *//* Init binding table * * INPUT VALUES: * * I01) maxbindings is negative * I02) maxbindings is zero * I03) maxlifetime is negative * I04) maxlifetime is zero (valid value) * I05) not enough memory for struct bindingtable (difficult to test autom.) *      - requires changes in code, will be tested manually * I06) maxbindings is too large for malloc to succeed (not enough memory) * I07) maxlifetime is too large for malloc to succeed (not enough memory) * I08) realistic values *//** * binding_init: * @maxbindings: * @maxlifetime: * * Initializes a bindingtable for storing bindings. * * Returns: A reference that is used in further operations on  *          the bindingtable. */struct bindingtable *binding_init(const int maxbindings, const int maxlifetime){	int i;	struct bindingtable *table;	if (maxbindings < 1) {		DEBUG(DEBUG_FLAG,		      "binding_init: maxbindings must be at least 1\n");		return NULL;	}	if (maxlifetime < 0) {		DEBUG(DEBUG_FLAG,		      "binding_init: maxlifetime must be positive\n");		return NULL;	}#ifdef BINDING_TEST_CASE_I05	table = NULL;#else	table = malloc(sizeof(struct bindingtable));#endif	if (table == NULL) {		DEBUG(DEBUG_FLAG,			"binding_init: not enough memory for "			"struct bindingtable\n");		return NULL;	}	i = (maxbindings > MAX_BINDING_HASH ? MAX_BINDING_HASH : maxbindings);	table->hashtablesize = hashtable_find_prime(2 * i);	ASSERT(table->hashtablesize > 0);	ASSERT(table->hashtablesize >= 2 * i);	table->hashtable = hashtable_init(table->hashtablesize);	if (table->hashtable == NULL) {		DEBUG(DEBUG_FLAG,			"binding_init: hash table creation failed\n");		free(table);		return NULL;	}	if (maxlifetime >= MAX_BINDING_SHORT_LIST)		table->shorttimelistsize = MAX_BINDING_SHORT_LIST;	else		table->shorttimelistsize = maxlifetime + 1;	table->shorttimelist = malloc(table->shorttimelistsize *				      sizeof(struct list));	if (table->shorttimelist == NULL) {		DEBUG(DEBUG_FLAG,			"binding_init: not enough memory for "			"a table of %d 'struct list' items\n",			table->shorttimelistsize);		hashtable_destroy(table->hashtable);		free(table);		return NULL;	}	for (i = 0; i < table->shorttimelistsize; i++) {		list_init(&table->shorttimelist[i]);	}	list_init(&table->longtimelist);	list_init(&table->noexptimelist);	table->firstindex = 0;	table->currentindex = 0;	return table;}/* Destroy all bindings * * NOTE! All entries must be removed before calling this! * * INPUT VALUES: * * I09) Table is empty * I10) Table is not empty (difficult to test automatically, assertions fail) *      - test will be done manually *//** * binding_destroy: * @table: * * Destroy all bindings. binding_destroy() should be called to destroy a * bindingtable when it is not needed any more. All entries from the table * must be removed before doing this. */voidbinding_destroy(struct bindingtable *table){	int i;	ASSERT(table != NULL);	for (i = 0; i < table->shorttimelistsize; i++) {		ASSERT(list_is_empty(&table->shorttimelist[i]) == TRUE);	}	ASSERT(list_is_empty(&table->longtimelist) == TRUE);	ASSERT(list_is_empty(&table->noexptimelist) == TRUE);	free(table->shorttimelist);	hashtable_destroy(table->hashtable);	free(table);}/* Add binding * * INPUT VALUES: * * I11) Timeout is less than zero * I12) Unable to add to hashtable (this requires a buggy hash function) *      - requires changes in code, test will be done manually * I13) Timeout is longer than shorttimelistsize * I14) Timeout is longer than maxuseshortlist (expired bindings exist) * I15) Timeout is a reasonable value (~ less than firstindex - currentindex) * *//** * binding_add: * @table: * @entry: * * Adds a bindingentry into the bindingtable. * * NOTE: Use binding_getexpired() to advance the timer to current time before * adding new bindings. And for optimal performance, process all expired * bindings before adding new ones. * * Returns: TRUE on success */intbinding_add(struct bindingtable *table, struct bindingentry *entry){	int idx, maxuseshortlist;	struct list *addlist;	ASSERT(table != NULL);	ASSERT(entry != NULL);	if (entry->timeout < 0) {		DEBUG(DEBUG_FLAG,			"binding_add: unable to add entry with timeout %d "			"that is less than zero\n",			entry->timeout);		return FALSE;	}	DEBUG(DEBUG_FLAG,	      "binding_add: entry = 0x%08x, &entry->mn_addr = 0x%08x\n",	      (int) entry, (int) &entry->mn_addr);	DEBUG(DEBUG_FLAG, "\tkey: (MN=%s,HA=", inet_ntoa(entry->mn_addr));	DEBUG(DEBUG_FLAG, "%s)\n", inet_ntoa(entry->ha_addr));	list_init_node(&entry->hashnode);	list_init_node(&entry->timenode);	if (hashtable_add(table->hashtable, binding_hash,			  &entry->mn_addr, &entry->hashnode) == FALSE) {		DEBUG(DEBUG_FLAG,			"binding_add: unable to add entry to hashtable\n");		return FALSE;	}	idx = table->currentindex;	ASSERT(idx >= 0);	ASSERT(idx < table->shorttimelistsize);	maxuseshortlist = table->firstindex + (table->shorttimelistsize - 1) -			  table->currentindex;	if (maxuseshortlist >= table->shorttimelistsize) {		maxuseshortlist -= table->shorttimelistsize;	}	DEBUG(DEBUG_FLAG,	      "binding_add: shorttimelistsize = %d, maxuseshortlist = %d\n",	      table->shorttimelistsize, maxuseshortlist);	ASSERT(maxuseshortlist >= 0);	ASSERT(maxuseshortlist < table->shorttimelistsize);	if (entry->timeout >= INFINITE_TIMEOUT)		addlist = &table->noexptimelist;	else		addlist = &table->longtimelist;	if (entry->timeout >= table->shorttimelistsize) {		DEBUG(DEBUG_FLAG,			"binding_add: timeout %d longer than "			"shorttimelistsize %d, long list used\n",			entry->timeout, table->shorttimelistsize);	} else if (entry->timeout > maxuseshortlist) {		DEBUG(DEBUG_FLAG,			"binding_add: timeout %d longer than "			"maxuseshortlist %d, long list used\n"			"binding_add: firstindex %d, currentindex %d\n",			entry->timeout, maxuseshortlist,			table->firstindex, table->currentindex);	} else {		ASSERT(entry->timeout < INFINITE_TIMEOUT);		idx = idx + entry->timeout;		if (idx >= table->shorttimelistsize) {			idx -= table->shorttimelistsize;		}		ASSERT(idx >= 0);		ASSERT(idx < table->shorttimelistsize);		addlist = &table->shorttimelist[idx];	}	list_add_tail(addlist, &entry->timenode);	return TRUE;}/* Fetch binding * * INPUT VALUES: * * I16) Bindingentry is not found * I17) Bindingentry is found * *//** * binding_fetch: * @table: * @key: * * Fetch binding. *  * Returns: a bindingentry structur if any binding for the requested * mobile node is found.   */struct bindingentry *binding_fetch(struct bindingtable *table, struct bindingkey *key){	struct bindingentry *entry;	struct node *node;	DEBUG(DEBUG_FLAG, "binding_fetch: key: (MN=%s,HA=",	      inet_ntoa(key->mn_addr));	DEBUG(DEBUG_FLAG, "%s,privHA=%i)\n", inet_ntoa(key->ha_addr),	      key->priv_ha);	node = hashtable_fetch(table->hashtable, binding_hash, key,			       binding_compare);	if (node == NULL) {		DEBUG(DEBUG_FLAG, "binding_fetch: entry %08x,%08x not found in"		      " the hashtable\n", key->mn_addr.s_addr,		      key->ha_addr.s_addr);		return NULL;	}	entry = (struct bindingentry *)		(((char *) node) - offsetof(struct bindingentry, hashnode));	return entry;}static struct bindingentry *found_binding;static int fetch_iter2(struct node *node, void *data){	struct bindingentry *entry = (struct bindingentry *) node;	struct in_addr *addr = (struct in_addr *) data;	if (entry->mn_addr.s_addr == addr->s_addr) {		found_binding = entry;		return 0;	}	return 1;}/** * binding_fetch2: * @table: * @mn_addr: *  * This function is like binding_fetch(), but it does not use the full * binding key (only @mn_addr). It is a temporary fix due to the binding key * change. It should also be noted, that this function has to go through all * the binding entries as it cannot use hashtable without proper key. * * Returns: a bindingentry structure * if any binding for the requested mobile node is found. */struct bindingentry *binding_fetch2(struct bindingtable *table, struct in_addr *mn_addr){	found_binding = NULL;	hashtable_iterator(table->hashtable, fetch_iter2, mn_addr);	if (found_binding == NULL) {		DEBUG(DEBUG_FLAG, "binding_fetch2: entry %08x not found in "		      "hashtable\n", mn_addr->s_addr);		return NULL;	}	return found_binding;}static int fetch_iter_func(struct node *node, void *data){	struct bindingentry *entry = (struct bindingentry *) node;	int (*func)(struct bindingentry *) = data;	if (func(entry)) {		found_binding = entry;		return 0;	}	return 1;}/** * binding_fetch_func: * @table: pointer to the binding table * @func: function to be used to select the binding *  * This function is like binding_fetch(), but it goes through all the binding * entries until a correct one is found. The given @func is used to decide * which binding entry is selected. * * Returns: a bindingentry structure for the selected binding or NULL if no * binding is selected. */struct bindingentry *binding_fetch_func(struct bindingtable *table,		   int (*func)(struct bindingentry *binding)){	found_binding = NULL;	hashtable_iterator(table->hashtable, fetch_iter_func, func);	if (found_binding == NULL) {		DEBUG(DEBUG_FLAG, "binding_fetch_func: entry not found in "		      "hashtable\n");		return NULL;	}	return found_binding;}/* Remove binding * * INPUT VALUES: * * I18) Bindingentry is valid *    ) Bindingentry is NULL

⌨️ 快捷键说明

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