Beispiel #1
0
int __exit mipv6_shutdown_bcache()
{
	unsigned long flags;
	struct mipv6_bcache_entry *entry;

	DEBUG_FUNC();

	write_lock_irqsave(&bcache->lock, flags);
	DEBUG((DBG_INFO, "mipv6_shutdown_bcache: Stopping the timer"));
	del_timer(&bcache->callback_timer);

	while ((entry = (struct mipv6_bcache_entry *) 
		hashlist_get_first(bcache->entries)) != NULL)
	{
		DEBUG_FUNC();
	/*	hashlist_delete_first(bcache->entries); */
		bcache_proxy_nd_rem(entry);
		hashlist_delete(bcache->entries, &entry->home_addr);
		mipv6_bcache_entry_free(entry);
		DEBUG_FUNC();
	}

	hashlist_destroy(bcache->entries);
	mipv6_free_allocation_pool(bcache->entry_pool);
#ifdef CONFIG_PROC_FS
	proc_net_remove("mip6_bcache");
#endif
	/* Lock must be released before freeing the memory. */
	write_unlock_irqrestore(&bcache->lock, flags);

	kfree(bcache);

	return 0;
}
Beispiel #2
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;
}
Beispiel #3
0
/**
 * mipv6_halist_delete - delete home agent from Home Agents List
 * @glob_addr: home agent's global address
 *
 * Deletes entry for home agent @glob_addr from the Home Agent List.
 **/
int mipv6_halist_delete(struct in6_addr *glob_addr)
{
	int ret;
	unsigned long flags;

	DEBUG_FUNC();

	if (glob_addr == NULL) {
		DEBUG((DBG_WARNING, "mipv6_halist_delete: invalid glob addr"));
		return -1;
	}

	write_lock_irqsave(&home_agents->lock, flags);
	ret = hashlist_delete(home_agents->entries, glob_addr);
	write_unlock_irqrestore(&home_agents->lock, flags);
	return ret;
}
Beispiel #4
0
/**
 * mipv6_bcache_delete - delete Binding Cache entry
 * @home_addr: MN's home address
 * @type: type of entry
 *
 * Deletes an entry associated with @home_addr from Binding Cache.
 * Valid values for @type are %CACHE_ENTRY, %HOME_REGISTRATION and
 * %ANY_ENTRY.  %ANY_ENTRY deletes any type of entry.
 **/
int mipv6_bcache_delete(struct in6_addr *home_addr, __u8 type) 
{
	unsigned long flags;
	struct mipv6_bcache_entry *entry;
  
	DEBUG_FUNC();

	if (home_addr == NULL || !is_valid_type(type)) {
		DEBUG((DBG_INFO, "error in arguments"));
		return -1;
	}

	write_lock_irqsave(&bcache->lock, flags);
	entry = (struct mipv6_bcache_entry *) 
		hashlist_get(bcache->entries, home_addr);
	if (entry == NULL) {
		DEBUG((DBG_INFO, "mipv6_bcache_delete: No such entry"));
		write_unlock_irqrestore(&bcache->lock, flags);
		return -1;
	}
  	if (!(entry->type & type)) {
		DEBUG((DBG_INFO, "mipv6_bcache_delete: No entry with "
		       "type correct type"));
		write_unlock_irqrestore(&bcache->lock, flags);
		return -1;
	}

	if (type == HOME_REGISTRATION) {
		mipv6_tunnel_route_del(&entry->home_addr, 
				       &entry->coa,
				       &entry->our_addr);
		mipv6_tunnel_del(&entry->coa, &entry->our_addr);
		bcache_proxy_nd_rem(entry);
	}
	hashlist_delete(bcache->entries, &entry->home_addr);
	mipv6_bcache_entry_free(entry);

	set_timer();
	write_unlock_irqrestore(&bcache->lock, flags);

	return 0;
} 
Beispiel #5
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;
}
Beispiel #6
0
/*
 * Removes all expired entries 
 */
static void expire(void)
{
	struct mipv6_bcache_entry *entry;
	unsigned long now = jiffies;
	unsigned long flags;
	struct br_addrs {
		struct in6_addr daddr;
		struct in6_addr saddr;
		struct br_addrs *next;
	};
	struct br_addrs *br_info = NULL;

	DEBUG_FUNC();

	write_lock_irqsave(&bcache->lock, flags);

	while ((entry = (struct mipv6_bcache_entry *)
		hashlist_get_first(bcache->entries)) != NULL) {
		if (entry->callback_time <= now) {
			DEBUG((DBG_INFO, "expire(): an entry expired"));
			if (entry->type & HOME_REGISTRATION) {
				mipv6_tunnel_route_del(&entry->home_addr,
						       &entry->coa,
						       &entry->our_addr);
				mipv6_tunnel_del(&entry->coa, &entry->our_addr);
				bcache_proxy_nd_rem(entry);
			}
			hashlist_delete(bcache->entries, &entry->home_addr);
			mipv6_bcache_entry_free(entry);
			entry = NULL;
		} else if (entry->br_callback_time != 0 &&
			   entry->br_callback_time <= now &&
			   entry->type & !(HOME_REGISTRATION | TEMPORARY_ENTRY)) {
			if (now - entry->last_used < BCACHE_BR_SEND_THRESHOLD * HZ) {
				struct br_addrs *tmp;

				tmp = br_info;
				DEBUG((DBG_INFO, "bcache entry recently used. Sending BR."));
				/* queue for sending */
				br_info = kmalloc(sizeof(struct br_addrs), GFP_ATOMIC);
				if (br_info) {
					ipv6_addr_copy(&br_info->saddr, &entry->our_addr);
					ipv6_addr_copy(&br_info->daddr, &entry->home_addr);
					br_info->next = tmp;
					entry->last_br = now;
				} else {
					br_info = tmp;
					DEBUG((DBG_ERROR, "Out of memory"));
				}
			}
			entry->br_callback_time = 0;
		} else {
			break;
		}
	}
	write_unlock_irqrestore(&bcache->lock, flags);

	while (br_info) {
		struct br_addrs *tmp = br_info->next;
		if (mipv6_send_rq_option(&br_info->saddr, &br_info->daddr, 0, NULL) < 0)
			DEBUG((DBG_WARNING, "BR send for %x:%x:%x:%x:%x:%x:%x:%x failed",
			       NIPV6ADDR(&br_info->daddr)));
		kfree(br_info);
		br_info = tmp;
	}

	return;
}