Ejemplo n.º 1
0
static int halist_proc_info(char *buffer, char **start, off_t offset,
                            int length)
{
	unsigned long flags;
	struct procinfo_iterator_args args;

	DEBUG_FUNC();

	args.buffer = buffer;
	args.offset = offset;
	args.length = length;
	args.skip = 0;
	args.len = 0;

	read_lock_irqsave(&home_agents->lock, flags);
	hashlist_iterate(home_agents->entries, &args, procinfo_iterator);
	read_unlock_irqrestore(&home_agents->lock, flags);

	*start = buffer;
	if (offset)
		*start += offset % HALIST_INFO_LEN;

	args.len -= offset % HALIST_INFO_LEN;

	if (args.len > length)
		args.len = length;
	if (args.len < 0)
		args.len = 0;
	
	return args.len;
}
Ejemplo n.º 2
0
/**
 * mipv6_ha_get_pref_list - Get list of preferred home agents
 * @ifindex: interface identifier
 * @addrs: pointer to a buffer to store the list
 * @max: maximum number of home agents to return
 *
 * Creates a list of @max preferred (or all known if less than @max)
 * home agents.  Home Agents List is interface specific so you must
 * supply @ifindex.  Stores list in addrs and returns number of home
 * agents stored.  On failure, returns a negative value.
 **/
int mipv6_ha_get_pref_list(int ifindex, struct in6_addr **addrs, int max)
{
	unsigned long flags;
	struct preflist_iterator_args args;

	if (max <= 0) {
		*addrs = NULL;
		return 0;
	}

	args.count = 0;
	args.requested = max;
	args.ifindex = ifindex;
	args.list = kmalloc(max * sizeof(struct in6_addr), GFP_ATOMIC);

	if (args.list == NULL) return -1;

	read_lock_irqsave(&home_agents->lock, flags);
	hashlist_iterate(home_agents->entries, &args, preflist_iterator);
	read_unlock_irqrestore(&home_agents->lock, flags);

	if (args.count >= 0) {
		*addrs = args.list;
	} else {
		kfree(args.list);
		*addrs = NULL;
	}

	return args.count;
}
Ejemplo n.º 3
0
/* 
 * Get memory for a new bcache entry.  If bcache if full, a cache
 * entry may deleted to get space for a home registration, but not
 * vice versa.
 */
static struct mipv6_bcache_entry *mipv6_bcache_get_entry(__u8 type) 
{
	struct mipv6_bcache_entry *entry;
	struct cache_entry_iterator_args args;

	DEBUG_FUNC();
  
	entry = (struct mipv6_bcache_entry *)
		mipv6_allocate_element(bcache->entry_pool);

	if (entry == NULL && type == HOME_REGISTRATION) {
                /* cache full, but need space for a home registration */
		args.entry = &entry;
		hashlist_iterate(bcache->entries, &args,
				 find_first_cache_entry_iterator);
		if (entry != NULL) {
			DEBUG((DBG_INFO, "cache entry: %x", entry));
			if (hashlist_delete(bcache->entries, &entry->home_addr) < 0)
				DEBUG((DBG_ERROR, "bcache entry delete failed"));
			else
				entry = (struct mipv6_bcache_entry *)
					mipv6_allocate_element(bcache->entry_pool);
		}
	}

	return entry;
}
Ejemplo n.º 4
0
/**
 * mipv6_halist_clean - remove all home agents for an interface
 * @ifindex: interface index
 *
 * Removes all Home Agents List entries for a given interface.
 **/
void mipv6_halist_clean(int ifindex)
{
	unsigned long flags;
	int args;

	args = ifindex;

	write_lock_irqsave(&home_agents->lock, flags);
	hashlist_iterate(home_agents->entries, &args, cleaner_iterator);
	write_unlock_irqrestore(&home_agents->lock, flags);
}
Ejemplo n.º 5
0
static int mipv6_halist_gc(int type)
{
	int args;

	DEBUG_FUNC();

	args = type;
	hashlist_iterate(home_agents->entries, &args, gc_iterator);

	return 0;
}
Ejemplo n.º 6
0
/*
 * Get Home Agent Address for an interface
 */
int mipv6_ha_get_addr(int ifindex, struct in6_addr *addr)
{
	unsigned long flags;
	struct getaddr_iterator_args args;
	struct net_device *dev;

	if (ifindex <= 0)
		return -1;

	if ((dev = dev_get_by_index(ifindex)) == NULL)
		return -1;

	memset(addr, 0, sizeof(struct in6_addr));
	args.dev = dev;
	args.addr = addr;
	read_lock_irqsave(&home_agents->lock, flags);
	hashlist_iterate(home_agents->entries, &args, getaddr_iterator);
#ifdef CONFIG_IPV6_MOBILITY_DEBUG
	printk(KERN_INFO "%s: interface = %s\n", __FUNCTION__, dev->name);
	printk(KERN_INFO "%s: home agent = %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", __FUNCTION__,
		ntohs(args.addr->s6_addr16[0]),
		ntohs(args.addr->s6_addr16[1]),
		ntohs(args.addr->s6_addr16[2]),
		ntohs(args.addr->s6_addr16[3]),
		ntohs(args.addr->s6_addr16[4]),
		ntohs(args.addr->s6_addr16[5]),
		ntohs(args.addr->s6_addr16[6]),
		ntohs(args.addr->s6_addr16[7]));
#endif
	read_unlock_irqrestore(&home_agents->lock, flags);
	dev_put(dev);

	if (ipv6_addr_any(addr))
		return -1;
	
	return 0;
}
Ejemplo n.º 7
0
/**
 * mipv6_mn_get_pref_ha - get preferred home agent for prefix
 * @prefix: prefix
 * @plen: prefix length
 *
 * Is this useful?
 **/
struct in6_addr *mipv6_mn_get_prefha(struct in6_addr *prefix, int plen)
{
	unsigned long flags;
	struct mipv6_halist_entry *entry = NULL;
	struct in6_addr *ha_addr;
	struct prefha_iterator_args args;

	DEBUG_FUNC();

	ha_addr = kmalloc(sizeof(struct in6_addr), GFP_ATOMIC);
	if (ha_addr == NULL) {
		return NULL;
	}

	ipv6_addr_copy(&args.prefix, prefix);
	args.plen = plen;

	read_lock_irqsave(&home_agents->lock, flags);

	/* search for HA in home subnet with highest preference */
	if (entry == NULL) {
		hashlist_iterate(home_agents->entries, &args, prefha_iterator);
		entry = args.entry;
	}
	/* no suitable HA could be found */
	if (entry == NULL) {
		read_unlock_irqrestore(&home_agents->lock, flags);
		kfree(ha_addr);
		return NULL;
	}

	ipv6_addr_copy(ha_addr, &entry->global_addr);
	read_unlock_irqrestore(&home_agents->lock, flags);

	return ha_addr;
}
Ejemplo n.º 8
0
/**
 * mipv6_bcache_add - add Binding Cache entry
 * @ifindex: interface index
 * @our_addr: own address
 * @home_addr: MN's home address
 * @coa: MN's care-of address
 * @lifetime: lifetime for this binding
 * @prefix: prefix length
 * @seq: sequence number
 * @single: single address bit
 * @type: type of entry
 *
 * Adds an entry for this @home_addr in the Binding Cache.  If entry
 * already exists, old entry is updated.  @type may be %CACHE_ENTRY or
 * %HOME_REGISTRATION.
 **/
int mipv6_bcache_add(
	int ifindex,
	struct in6_addr *our_addr,
	struct in6_addr *home_addr,
	struct in6_addr *coa,
	__u32 lifetime,
	__u8 prefix,
	__u8 seq,
	__u8 single,
	__u8 type) 
{
	unsigned long flags;
	struct mipv6_bcache_entry *entry;
	int update = 0;
	int create_tunnel = 0;
	unsigned long now = jiffies;
	struct cache_entry_iterator_args args;

	write_lock_irqsave(&bcache->lock, flags);

	if ((entry = (struct mipv6_bcache_entry *)
	     hashlist_get(bcache->entries, home_addr)) != NULL) {
                /* if an entry for this home_addr exists (with smaller
		 * seq than the new seq), update it by removing it
		 * first
		 */
		if (SEQMOD(seq, entry->seq)) {
			DEBUG((DBG_INFO, "mipv6_bcache_add: updating an "
			       "existing entry"));
			update = 1;

			if (entry->type == HOME_REGISTRATION) {
				create_tunnel = ipv6_addr_cmp(&entry->our_addr,
							      our_addr) ||
					ipv6_addr_cmp(&entry->coa, coa) ||
					entry->ifindex != ifindex || 
					entry->prefix != prefix || 
					entry->single != single;
				if (create_tunnel || 
				    type != HOME_REGISTRATION) {
					mipv6_tunnel_route_del(
						&entry->home_addr, 
						&entry->coa,
						&entry->our_addr);
					mipv6_tunnel_del(&entry->coa, 
							 &entry->our_addr);
				}				
				if (type != HOME_REGISTRATION) {
					bcache_proxy_nd_rem(entry);
				}
			}
		} else {
			DEBUG((DBG_INFO, "mipv6_bcache_add: smaller seq "
			       "than existing, not updating"));
/*
			write_unlock_irqrestore(&bcache->lock, flags);
			return 0;
*/
		}
	} else {
		/* no entry for this home_addr, try to create a new entry */
		DEBUG((DBG_INFO, "mipv6_bcache_add: creating a new entry"));
		entry = mipv6_bcache_get_entry(type);
		
		if (entry == NULL) {
			/* delete next expiring entry of type CACHE_ENTRY */
			args.entry = &entry;
			hashlist_iterate(bcache->entries, &args,
			                 find_first_cache_entry_iterator);

			if (entry == NULL) {
				DEBUG((DBG_INFO, "mipv6_bcache_add: cache full"));
				write_unlock_irqrestore(&bcache->lock, flags);
				return -1;
			}
			hashlist_delete(bcache->entries, &entry->home_addr);
		}
		create_tunnel = (type == HOME_REGISTRATION);
	}
	
	ipv6_addr_copy(&(entry->our_addr), our_addr);
	ipv6_addr_copy(&(entry->home_addr), home_addr);
	ipv6_addr_copy(&(entry->coa), coa);
	entry->ifindex = ifindex;
	entry->prefix = prefix;
	entry->seq = seq;
	entry->type = type;
	entry->last_used = 0;

	if (type == HOME_REGISTRATION) {
		entry->router = 0;
		entry->single = single;
		if (create_tunnel) {
			if (mipv6_tunnel_add(coa, our_addr, 0)) {
				DEBUG((DBG_INFO, "mipv6_bcache_add: no free tunnel devices!"));
				bcache_proxy_nd_rem(entry);
				if (update) 
					hashlist_delete(bcache->entries, 
							&entry->home_addr);
				mipv6_bcache_entry_free(entry);

				write_unlock_irqrestore(&bcache->lock, flags);
				return -1;
			}
			/* Todo: set the prefix length correctly */
			if (mipv6_tunnel_route_add(home_addr, 
						   coa, 
						   our_addr)) {
				DEBUG((DBG_INFO, "mipv6_bcache_add: invalid route to home address!"));
				mipv6_tunnel_del(coa, our_addr);
				bcache_proxy_nd_rem(entry);

				if (update) 
					hashlist_delete(bcache->entries, 
							&entry->home_addr);
				mipv6_bcache_entry_free(entry);

				write_unlock_irqrestore(&bcache->lock, flags);
				return -1;
			}
		}
	}
	entry->last_br = 0;
	if (lifetime == EXPIRE_INFINITE) {
		entry->callback_time = EXPIRE_INFINITE; 
	} else {
		entry->callback_time = now + lifetime * HZ;
		if (entry->type & (HOME_REGISTRATION | TEMPORARY_ENTRY))
			entry->br_callback_time = 0;
		else
			entry->br_callback_time = now + 
				(lifetime - BCACHE_BR_SEND_LEAD) * HZ;
	}

	if (update) {
		DEBUG((DBG_INFO, "updating entry : %x", entry));
		hashlist_reschedule(bcache->entries,
		                    home_addr,
		                    entry->callback_time);
	} else {
		DEBUG((DBG_INFO, "adding entry: %x", entry));
		if ((hashlist_add(bcache->entries,
				  home_addr,
				  entry->callback_time,
				  entry)) < 0) {
			if (create_tunnel) {
				mipv6_tunnel_route_del(home_addr, 
						       coa, 
						       our_addr);
				mipv6_tunnel_del(coa, our_addr);
				bcache_proxy_nd_rem(entry);
			}
			mipv6_bcache_entry_free(entry);
			DEBUG((DBG_ERROR, "Hash add failed"));
			write_unlock_irqrestore(&bcache->lock, flags);
			return -1;
		}
	}

	set_timer();

	write_unlock_irqrestore(&bcache->lock, flags);
	return 0;
}