Пример #1
0
static int procinfo_iterator(void *data, void *args,
			     struct in6_addr *addr, 
			     unsigned long *pref)
{
	struct procinfo_iterator_args *arg =
		(struct procinfo_iterator_args *)args;
	struct mipv6_bcache_entry *entry =
		(struct mipv6_bcache_entry *)data;

	DEBUG_FUNC();

	if (entry == NULL) return ITERATOR_ERR;

	if (entry->type == TEMPORARY_ENTRY)
		return ITERATOR_CONT;

	if (arg->skip < arg->offset / BC_INFO_LEN) {
		arg->skip++;
		return ITERATOR_CONT;
	}

	if (arg->len >= arg->length)
		return ITERATOR_CONT;

	arg->len += sprintf(arg->buffer + arg->len, 
			"h=%04x%04x%04x%04x%04x%04x%04x%04x "
			"c=%04x%04x%04x%04x%04x%04x%04x%04x "
			"(e=%010lu,t=%02d)\n",
			NIPV6ADDR(&entry->home_addr),
			NIPV6ADDR(&entry->coa),
			((entry->callback_time) - jiffies) / HZ,
			(int)entry->type);

	return ITERATOR_CONT;
}
Пример #2
0
void mipv6_check_tunneled_packet(struct sk_buff *skb)
{

	DEBUG_FUNC();
	/* If tunnel flag was set */
	if (skb->security & RCV_TUNNEL) {
		struct in6_addr coa; 
		__u32 lifetime;
		mipv6_get_care_of_address(&skb->nh.ipv6h->daddr, &coa);
		lifetime = mipv6_mn_get_bulifetime(&skb->nh.ipv6h->daddr,
 							 &coa, 0); 

		DEBUG((DBG_WARNING, "packet was tunneled. Sending BU to CN" 
		       "%x:%x:%x:%x:%x:%x:%x:%x", 
		       NIPV6ADDR(&skb->nh.ipv6h->saddr))); 
		/* This should work also with home address option */
		mipv6_send_upd_option(
			&skb->nh.ipv6h->daddr,
			&skb->nh.ipv6h->saddr,
			CN_BU_DELAY, INITIAL_BINDACK_TIMEOUT,
			MAX_BINDACK_TIMEOUT, 1, 
#ifdef CN_REQ_ACK
			MIPV6_BU_F_ACK, /* ack */
#else
			0, /* no ack */
#endif
			64, lifetime, NULL);
	}
}
Пример #3
0
/**
 * mn_handoff - called for every bul entry to send BU to CN
 * @rawentry: bul entry
 * @args: handoff event
 * @hashkey:
 * @sortkey:
 *
 * Since MN can have many home addresses and home networks, every BUL entry 
 * needs to be checked   
 **/
static int mn_handoff(void *rawentry, void *args,
		 struct in6_addr *hashkey,
		 unsigned long *sortkey)
{
	__u32 lifetime;
	int athome;
	struct mipv6_bul_entry *entry = (struct mipv6_bul_entry *)rawentry;
	struct handoff *ho = (struct handoff *)args;
	int pfixlen = 64; /* Get the prefixlength instead of fixed 64 bits */
	athome = mipv6_prefix_compare(&ho->rtr_new.raddr, &entry->home_addr, 
				      pfixlen);

	if (!athome) {
		lifetime = mipv6_mn_get_bulifetime(&entry->home_addr, 
						   &ho->rtr_new.CoA,
						   entry->flags);
	}
	else {
		lifetime = 0;
		entry->flags = entry->flags | MIPV6_BU_F_DEREG;
	}

	if (entry->flags & MIPV6_BU_F_HOME) {
		DEBUG((DBG_INFO, "Sending home de ? %d registration for "
		       "home address: %x:%x:%x:%x:%x:%x:%x:%x\n" 
		       "to home agent %x:%x:%x:%x:%x:%x:%x:%x, "
		       "with lifetime %ld, prefixlength %d", athome,  
		       NIPV6ADDR(&entry->home_addr), 
		       NIPV6ADDR(&entry->cn_addr), lifetime, entry->prefix));
		mipv6_send_upd_option(
			&entry->home_addr, &entry->cn_addr, HA_BU_DELAY, 
			INITIAL_BINDACK_TIMEOUT, MAX_BINDACK_TIMEOUT, 1,
			entry->flags, entry->prefix, lifetime, NULL);
	}
	else {
		DEBUG((DBG_INFO, "Sending BU for home address: %x:%x:%x:%x:%x:%x:%x:%x \n" 
		       "to CN: %x:%x:%x:%x:%x:%x:%x:%x, "
		       "with lifetime %ld",   NIPV6ADDR(&entry->home_addr), 
		       NIPV6ADDR(&entry->cn_addr), lifetime));
		mipv6_send_upd_option(
			&entry->home_addr, &entry->cn_addr, CN_BU_DELAY, 
			INITIAL_BINDACK_TIMEOUT, MAX_BINDACK_TIMEOUT, 1,
			entry->flags, entry->prefix, lifetime, NULL);
	}

	return ITERATOR_CONT;
}
Пример #4
0
int mipv6_parse_opts(struct in6_addr *CoA, __u8 *ptr,__u8 *end, __u8 send)
{
           DEBUG_FUNC();
	   ptr += 2; /* To skip to option type */
	   
	   while (ptr < end){ 
		   DEBUG((AH_PARSE,"dst or hbh opt of type: %x", ptr[0]));
		   
		   /*  if (opt_len > end - ptr){
			   DEBUG((DBG_ERROR, " opt of incorrect length ?"));
			   return -1;
			   }*/
		   if (ptr && ptr[0] & 0x20){ /* mutable */
			   DEBUG((AH_PARSE, "Mutable dest. or hop option"));
			   DEBUG((AH_PARSE, "Of type: %x", ptr[0]));
			   /*   memset(ptr,0,ptr[1] + 2);  Set option to zero */

		   }
		   /* Swap home address and CoA */
		   if (ptr[0] == 0xc9 && send) {			   
			   struct in6_addr coa;
			   if(!CoA || !(ptr + 2)) {
				   DEBUG((DBG_ERROR, "AH calc got null saddr or home address opt"));
				   return -1;
			   }
			   ipv6_addr_copy(&coa, CoA);
			   ipv6_addr_copy(CoA, 
					  ((struct in6_addr *)(&ptr[2])));
			   DEBUG((AH_PARSE, "Setting source address to " 
				  "%x:%x:%x:%x:%x:%x:%x:%x", 
				  NIPV6ADDR(CoA)));
			   ipv6_addr_copy((struct in6_addr *)(&ptr[2]), 
					  &coa);
			   DEBUG((AH_PARSE, "Setting home address to " 
				  "%x:%x:%x:%x:%x:%x:%x:%x", 
				  NIPV6ADDR((struct in6_addr *)(&ptr[2]))));
		   }
		   
		   /* length of option + length of type and length fields*/
		   ptr = ptr + ptr[1] + 2;  
	   }
	   return 0;
}
Пример #5
0
/**
 * init_home_registration - start Home Registration process
 * @hinfo: mn_info entry for the home address
 * @coa: care-of address
 *
 * Checks whether we have a Home Agent address for this home address.
 * If not starts Dynamic Home Agent Address Discovery.  Otherwise
 * tries to register with home agent if not already registered.
 **/
int init_home_registration(struct mn_info *hinfo, struct in6_addr *coa)
{
	__u32 lifetime;

	if (mipv6_prefix_compare(&hinfo->home_addr, coa, hinfo->home_plen)) { 
		hinfo->is_at_home = 1;
		DEBUG((DBG_INFO, "Adding home address, MN at home"));
		return 0;
	}

	if (ipv6_addr_any(&hinfo->ha)) {
		DEBUG((DBG_INFO, "Home Agent address not set, initiating DHAAD"));
		mipv6_mn_dhaad_send_req(&hinfo->home_addr, hinfo->home_plen, &hinfo->dhaad_id);
	} else {
		struct mipv6_bul_entry *bul = mipv6_bul_get(&hinfo->ha);
		if (bul) {
			if (!ipv6_addr_cmp(&bul->home_addr, &hinfo->home_addr)){
				DEBUG((DBG_INFO, "BU already sent to HA"));
				mipv6_bul_put(bul);
				return 0;
			}
			mipv6_bul_put(bul);
		}
		lifetime = mipv6_mn_get_bulifetime(
			&hinfo->home_addr, coa, 
			MIPV6_BU_F_HOME | MIPV6_BU_F_ACK);
		DEBUG((DBG_INFO, "Sending initial home registration for "
		       "home address: %x:%x:%x:%x:%x:%x:%x:%x\n" 
		       "to home agent %x:%x:%x:%x:%x:%x:%x:%x, "
		       "with lifetime %ld, prefixlength %d",   
		       NIPV6ADDR(&hinfo->home_addr), 
		       NIPV6ADDR(&hinfo->ha), lifetime, 0));
		mipv6_send_upd_option(
			&hinfo->home_addr, &hinfo->ha, 
			HA_BU_DELAY, 
			INITIAL_BINDACK_DAD_TIMEOUT, 
			MAX_BINDACK_TIMEOUT, 1,
			MIPV6_BU_F_HOME | MIPV6_BU_F_ACK | MIPV6_BU_F_DAD, 
			0, lifetime, NULL);
	}
	return 0;
}
Пример #6
0
static int procinfo_iterator(void *data, void *args,
			     struct in6_addr *addr, 
			     unsigned long *pref)
{
	struct procinfo_iterator_args *arg =
		(struct procinfo_iterator_args *)args;
	struct mipv6_halist_entry *entry =
		(struct mipv6_halist_entry *)data;
	int expire;

	DEBUG_FUNC();

	if (entry == NULL) return ITERATOR_ERR;

	if (time_after(jiffies, entry->expire))
		return ITERATOR_DELETE_ENTRY;

	if (arg->skip < arg->offset / HALIST_INFO_LEN) {
		arg->skip++;
		return ITERATOR_CONT;
	}

	if (arg->len >= arg->length)
		return ITERATOR_CONT;

	expire = (entry->expire - jiffies) / HZ;

	arg->len += sprintf(arg->buffer + arg->len, 
			"%02d %04x%04x%04x%04x%04x%04x%04x%04x "
			"%04x%04x%04x%04x%04x%04x%04x%04x %05d %05d\n",
			entry->ifindex,
			NIPV6ADDR(&entry->global_addr), 
			NIPV6ADDR(&entry->link_local_addr), 
			-(entry->preference - PREF_BASE), expire);

	return ITERATOR_CONT;
}
Пример #7
0
/* Used for sending, sets seq number to network byte order */
static void seq_incr(struct sec_as *sa, __u32 *seq){
	unsigned long flags;
	spin_lock_irqsave(&seq_lock, flags);
	/* TODO: Handle wraparound */
	sa->replay_count++;
	*seq = htonl(sa->replay_count);
	spin_unlock_irqrestore(&seq_lock, flags);
	if (sa->replay_count == 0) {
		DEBUG((DBG_ERROR, "Sequence number wraparound for" 
		       "outbound security association with address" 
		       "%x:%x:%x:%x:%x:%x:%x:%x", 
		       NIPV6ADDR(&sa->addr)));
		/* TODO: start sa_acquire */
	}
}
Пример #8
0
static int mipv6_mn_tunnel_rcv_send_bu_hook(
	struct ipv6_tunnel *t, struct sk_buff *skb, __u32 flags)
{
	struct ipv6hdr *inner = (struct ipv6hdr *)skb->h.raw;
	struct ipv6hdr *outer = skb->nh.ipv6h; 
	struct mn_info *minfo = NULL;
	__u32 lifetime;

	DEBUG_FUNC();
	if (!(flags & IPV6_T_F_MIPV6_DEV))
		return IPV6_TUNNEL_ACCEPT;

	read_lock(&mn_info_lock);
	minfo = mipv6_mn_get_info(&inner->daddr);

	if (!minfo) {
		DEBUG((DBG_WARNING, "MN info missing"));
		read_unlock(&mn_info_lock);
		return IPV6_TUNNEL_ACCEPT;
	}
	/* We don't send bus in response to all tunneled packets */

        if (!ipv6_addr_cmp(&minfo->ha, &inner->saddr)) {
                DEBUG((DBG_ERROR, "HA BUG: Received a tunneled packet "
		       "originally sent by home agent, not sending BU"));
		read_unlock(&mn_info_lock);
		return IPV6_TUNNEL_ACCEPT;
        }
	if (ipv6_addr_cmp(&minfo->ha, &outer->saddr)) {
		DEBUG((DBG_WARNING, "MIPV6 MN: Received a tunneled IPv6 packet"
		       " that was not tunneled by HA %x:%x:%x:%x:%x:%x:%x:%x,"
		       " but by %x:%x:%x:%x:%x:%x:%x:%x", 
		       NIPV6ADDR(&minfo->ha), NIPV6ADDR(&outer->saddr)));
		read_unlock(&mn_info_lock);
		return IPV6_TUNNEL_ACCEPT;
        }
	read_unlock(&mn_info_lock);

	DEBUG((DBG_INFO, "Sending BU to correspondent node"));

	if (inner->nexthdr != IPPROTO_DSTOPTS) {
		DEBUG((DBG_INFO, "Received tunneled packet without dst_opts"));
		lifetime = mipv6_mn_get_bulifetime(&inner->daddr,
						   &outer->daddr, 0); 
		if(lifetime)
		/* max wait 1000 ms  before sending an empty packet with BU */
			mipv6_send_upd_option(&inner->daddr,&inner->saddr,
					      CN_BU_DELAY, 
					      INITIAL_BINDACK_TIMEOUT,
					      MAX_BINDACK_TIMEOUT , 1, 
#ifdef CN_REQ_ACK
					      MIPV6_BU_F_ACK, /* ack */
#else
					      0, /* no ack */
#endif
					      0, lifetime, NULL);
	}
	/* (Mis)use ipsec tunnel flag  */
	DEBUG((DBG_INFO, "setting rcv_tunnel flag in skb"));
	skb->security = skb->security | RCV_TUNNEL;
	return IPV6_TUNNEL_ACCEPT;
}
Пример #9
0
/* Prepares the data for ah icv and returns pointeres both to the skb->ah and buff->ah */  
struct sk_buff *mipv6_prepare_dgram(struct sk_buff **pskb, 
				    struct mipv6_ah **ah_orig, 
				    struct mipv6_ah **ah, 
				    __u8 send)
{
	struct sk_buff *buff=NULL;
	__u8 *ptr,nhdr;
	unsigned int len, optlen;
	
	DEBUG_FUNC();
	
	if (!(*pskb)){
		DEBUG((DBG_WARNING,"mipv6_prepare_dgram: Got null skb as argument"));
		return NULL;
	}
	  buff = skb_copy(*pskb, GFP_ATOMIC);
	  if (!buff || !buff->nh.ipv6h){
		  DEBUG((DBG_ERROR, "mipv6_prepare_dgram: buff or ipv6 header was null")); 
		  return NULL;
	  }

	len = ntohs(buff->nh.ipv6h->payload_len) + sizeof(struct ipv6hdr);
	ptr = (__u8*)buff->nh.ipv6h + sizeof(struct ipv6hdr);


	if (!ptr){
		DEBUG((DBG_ERROR, "mipv6_prepare_dgram: pointer to nexthdr was null"));
		return NULL;
	}

	nhdr = buff->nh.ipv6h->nexthdr;
	buff->nh.ipv6h->hop_limit = 0;
	buff->nh.ipv6h->tclass1 = 0;
	memset(buff->nh.ipv6h->tclass2_flow, 0, 3);
	
	while (nhdr != NEXTHDR_NONE) {
		switch (nhdr) {

		case NEXTHDR_HOP:
		case NEXTHDR_DEST:
			/* Check mutability and if 1 replace with zeroes */
			optlen = (ptr[1] + 1) << 3;
			debug_print_buffer(DBG_DATADUMP, (void *)ptr, optlen);
			if(ptr + optlen > (__u8 *)buff->nh.ipv6h + len){
				DEBUG((DBG_WARNING, "Invalid opt.len %x, ptr: %x , buff->tail %x", optlen, ptr, buff->tail));
				return NULL;
			}
			DEBUG((AH_DUMP, "source address before parse opts " 
			       "%x:%x:%x:%x:%x:%x:%x:%x", 
			       NIPV6ADDR(&buff->nh.ipv6h->saddr)));
			mipv6_parse_opts(&buff->nh.ipv6h->saddr, ptr, 
					 ptr + optlen, send); 
			DEBUG((AH_PARSE, "AH calc set source address to " 
			       "%x:%x:%x:%x:%x:%x:%x:%x", 
			       NIPV6ADDR(&buff->nh.ipv6h->saddr)));
			
			/* Print the option */  

			nhdr = *ptr;
			ptr += optlen;
			break;
			
		case NEXTHDR_ROUTING:
			/* swap addresses etc. */
			optlen = ((ptr[1] +1) << 3);

			if(ptr + optlen > (__u8 *)buff->nh.ipv6h + len) {
				DEBUG((DBG_ERROR, 
				       "received rt header with incorrect length!"));
				return NULL;
			}
			/* We don't process incoming rt headers */  
			if (send && mipv6_ah_rt_header((struct rt0_hdr *)ptr, 
					       &buff->nh.ipv6h->daddr) < 0)
				return NULL;
			
			nhdr = *ptr;
			ptr += optlen;
			break; 
			
		case NEXTHDR_FRAGMENT:
			/* barf */
			DEBUG((DBG_ERROR, 
				       "Don't know how to handle fragmentation header"));
			return NULL;
			
		case NEXTHDR_AUTH:
			
			optlen = ((ptr[1]+2)<<2);
			if(ptr + optlen >  (__u8 *)buff->nh.ipv6h + len) {
				DEBUG((DBG_ERROR, 
				       "received auth header with incorrect length!"));
				return NULL;
			}
			/* We calculate the corresponding location in the 
			 *  original unmodified skb and add the AH pointer
			 */
			*ah_orig = (struct mipv6_ah*)ptr;
			*ah = (struct mipv6_ah*)(
				(__u8*)((*pskb)->nh.ipv6h) + 
				(ptr - (__u8*)(buff->nh.ipv6h)));   
			nhdr = *ptr;
			debug_print_buffer(AH_DUMP, (void*)ptr, optlen);
			ptr += optlen;
			return buff;
			DEBUG((AH_PARSE, "returning buff. "));
		default:
			/* Payload or unknown ext.hdrs*/
			return buff;
		}
	}
	DEBUG((AH_PARSE,"No next header to process\n"));
	return buff;
}
Пример #10
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;
}