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

📄 fa_utils.c

📁 mobile ip 在linux下的一种实现
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (t_data->is_lowest_fa && !t_data->arpentry) {		struct sockaddr hwaddr;		DEBUG(DEBUG_FLAG, "Adding ARP entry\n");		memset(&hwaddr, 0, sizeof(hwaddr));		hwaddr.sa_family = ARPHRD_ETHER;		memcpy(hwaddr.sa_data, t_data->info.from.sll_addr,		       t_data->info.from.sll_halen);		t_data->arp_ipaddr.s_addr = t_data->info.src.sin_addr.s_addr;		memcpy(t_data->arp_dev, t_data->info.iface->dev,		       sizeof(t_data->arp_dev));		if (arp_add_permanent_item(t_data->arp_ipaddr,					   t_data->arp_dev,					   &hwaddr) < 0) {			LOG2(LOG_WARNING,			     "Could not add ARP entry (%s, %s, %s)\n",			     inet_ntoa(t_data->arp_ipaddr),			     t_data->arp_dev,			     ether_hwtoa((unsigned char *) hwaddr.sa_data));		} else			t_data->arpentry = 1;	}#ifdef DYNAMICS_SET_MAIN_TABLE_MN_ROUTE	/* add also a route entry to the main routing table to the LFA if	 * MN is using FA decaps */	/* Also this should have been done in handle request phase */	if (t_data->fa_decapsulation &&	    dyn_ip_route_replace(binding->mn_addr, dev) == -1) {		LOG2(LOG_WARNING, "create_tunnels: dyn_ip_route_replace "		     "failed.\n");		return -1;	}#endif /* DYNAMICS_SET_MAIN_TABLE_MN_ROUTE */	/* Create tunnel upwards and connect the lower tunnel */	/* This is "new". In handle request phase only the downstream	 * is handled but here we take care of the upstream also. */	if (create_tunnel_upwards(binding, thash, highest_FA) < 0) {		LOG2(LOG_WARNING,		     "create_tunnels: create_tunnel_upwards failed.\n");		return -1;	}	return 0;}/** * add_unconfirmed_data: * @bhash:  * @bcounters:  * @binding:  * @ext:  * @info:  * @config:  *  * Allocates memory to an unconfirmed_request. *  * Returns: Pointer to an unconfirmed_request, or NULL on error. */struct unconfirmed_request *add_unconfirmed_data(struct bindingtable *bhash,		     struct binding_counters *bcounters,		     struct bindingentry *binding, struct msg_extensions *ext,		     struct packet_from_info *info,		     struct fa_config *config){	struct tunnel_data *t_data;	struct unconfirmed_request *unc;	int maxlifetime;	time_t now;	DEBUG(DEBUG_FLAG, "Adding unconfirmed request data\n");	t_data = binding->data;	time(&now);	binding->mod_time = now;	unc = (struct unconfirmed_request *)		malloc(sizeof(struct unconfirmed_request));	if (unc == NULL)		return NULL;	memset(unc, 0, sizeof(struct unconfirmed_request));	memcpy(&unc->info, info, sizeof(*info));	memcpy(&unc->req, ext->req, sizeof(struct reg_req));	if (ext->challenge) {		int n = GET_CHALLENGE_EXT_LEN(ext->challenge);		unc->challenge = (struct challenge_ext *) malloc(n);		if (unc->challenge == NULL) {			DEBUG(DEBUG_FLAG, "\tmalloc for challenge failed\n");			free(unc);			return NULL;		}		memcpy(unc->challenge, ext->challenge, n);	}	unc->next = t_data->unc_req;	unc->created = now;	unc->id[0] = ntohl(ext->req->id[0]);	unc->id[1] = ntohl(ext->req->id[1]);	if (ext->mh_auth != NULL)		unc->spi = ntohl(ext->mh_auth->spi);	unc->ha_addr = ext->req->ha_addr;	unc->timeout = ntohs(ext->req->lifetime);	if ((ext->req->opts & REGREQ_REVERSE_TUNNEL) != 0 || 	    config->force_reverse_tunneling)		unc->tunnel_mode = TUNNEL_MODE_REVERSE;	else		unc->tunnel_mode = TUNNEL_MODE_TRIANGLE;	unc->is_lowest_fa = is_sender_mobile(ext);	if (unc->is_lowest_fa)		DEBUG(DEBUG_FLAG,		      "\tassuming lowest FA (i.e. request from MN)\n");	else		DEBUG(DEBUG_FLAG,		      "\tassuming not lowest FA (i.e. request from FA)\n");	/* only use FA decapsulation if this is the lowest FA and MN	 * requests it */	unc->fa_decapsulation = unc->is_lowest_fa &&		(ext->req->opts & REGREQ_MN_DECAPS) == 0;	unc->encaps_delivery = !unc->is_lowest_fa || ext->encaps_del != NULL;	unc->old_if_index = info->iface->if_index;	unc->mn_nai_included = ext->mn_nai != NULL;	if (ext->fa_pubkey) {		unc->fa_pubkey = (struct msg_key *)			malloc(GET_KEY_EXT_LEN(ext->fa_pubkey));		if (unc->fa_pubkey != NULL) {			memcpy(unc->fa_pubkey, ext->fa_pubkey,			       GET_KEY_EXT_LEN(ext->fa_pubkey));		} else {			LOG2(LOG_ALERT, "add_unconfirmed_data - not enough "			     "memory\n");			if (unc->challenge)				free(unc->challenge);			free(unc);			return NULL;		}	} else if (ext->fa_keyreq) {		unc->fa_spi = ntohl(ext->fa_keyreq->spi);	}	if (ext->gre_key != NULL) {		unc->tunnel_type = TUNNEL_GRE;		unc->tunnel_key = ntohl(ext->gre_key->key);	} else 	if (unc->fa_decapsulation && !unc->encaps_delivery) {		unc->tunnel_type = TUNNEL_NO_ENCAPS;		unc->tunnel_key = info->iface->if_index;	} else {		unc->tunnel_type = TUNNEL_IPIP;		unc->tunnel_key = 0;	}	t_data->unc_req = unc;	maxlifetime = ntohs(ext->req->lifetime);	if (config->delete_pending_after > 0 &&	    config->delete_pending_after < maxlifetime)		maxlifetime = config->delete_pending_after;#ifdef SHORT_BINDING_DELAY_TIME	/* for testing - update lifetime even if binding is confirmed */	if (#else	if (!t_data->confirmed &&#endif	    binding->exp_time - now < maxlifetime) {		/* update the unconfirmed binding timeout so that extra		 * requests will not cause unwanted timeouts */		DEBUG(DEBUG_FLAG, "\tupdated binding lifetime %i => %i\n",		      binding->timeout, maxlifetime);		binding->timeout = maxlifetime;		binding->exp_time = now + binding->timeout;		if (update_binding(bhash, binding, bcounters) != 0)			return NULL;	}	return unc;}/** * unconfirmed_to_binding: * @binding:  * @unc:  *  *  */voidunconfirmed_to_binding(struct bindingentry *binding,		       struct unconfirmed_request *unc){	struct tunnel_data *t_data = binding->data;	binding->lower_addr = unc->info.src.sin_addr;	binding->lower_port = unc->info.src.sin_port;	memcpy(&t_data->info, &unc->info, sizeof(unc->info));#ifdef USE_TEARDOWN	t_data->upper_id[0] = binding->id[0] = unc->id[0];	t_data->upper_id[1] = binding->id[1] = unc->id[1];#endif	binding->spi = unc->spi;	binding->fa_spi = unc->fa_spi;	t_data->tunnel_mode = unc->tunnel_mode;	t_data->fa_decapsulation = unc->fa_decapsulation;	t_data->encaps_delivery = unc->encaps_delivery;	t_data->is_lowest_fa = unc->is_lowest_fa;	binding->ha_addr = unc->ha_addr;	if (t_data->fa_pubkey != NULL)		free(t_data->fa_pubkey);	t_data->fa_pubkey = unc->fa_pubkey;	unc->fa_pubkey = NULL;	if (t_data->last_sent_fa_pubkeyrep != NULL) {		free(t_data->last_sent_fa_pubkeyrep);		t_data->last_sent_fa_pubkeyrep = NULL;	}	t_data->last_used_seq_num = 0;	t_data->req_lifetime = unc->timeout;	t_data->old_if_index = unc->old_if_index;	setup_device_forcing(t_data);	t_data->down_type = unc->tunnel_type;	DEBUG(DEBUG_FLAG, "unconfirmed_to_binding: down_key - %i=>%i\n",	      t_data->down_key, unc->tunnel_key);	t_data->down_key = unc->tunnel_key;}/** * check_unconfirmed_timeout: * @binding: * * check if given binding has unconfirmed requests that have timeouted * and remove them  */voidcheck_unconfirmed_timeout(struct bindingentry *binding){	time_t now;	struct tunnel_data *t_data;	struct unconfirmed_request *unc, *prev;	time(&now);	t_data = binding->data;	unc = t_data->unc_req;	prev = NULL;	while (unc != NULL) {		if (now - unc->created > UNCONFIRMED_TIMEOUT) {			DEBUG(DEBUG_FLAG, "Freeing unconfirmed requests that "			      "have timed out\n");			free_unconfirmed_data(unc);			if (prev == NULL)				t_data->unc_req = NULL;			else				prev->next = NULL;			break;		}		prev = unc;		unc = unc->next;	}}/** * remove_binding_tunnels: * @binding:  * @thash:  * @bcounters:  *  *  */voidremove_binding_tunnels(struct bindingentry *binding, struct hashtable *thash,		       struct binding_counters *bcounters){	struct tunnel_data *t_data;	struct in_addr dst_addr, mn_addr, ha_addr;	int up_type;	__u32 up_key ;	t_data = binding->data;	up_type = t_data->up_type;	up_key = t_data->up_key;	if (t_data->up_tunl)		dst_addr = t_data->up_tunl->dst_addr;	else		dst_addr.s_addr = 0;	/* Remove possible tunnel upwards to HA also */	mn_addr.s_addr = binding->mn_addr.s_addr;	ha_addr.s_addr = binding->ha_addr.s_addr;	eliminate_binding_entry((struct node *) binding, bcounters);}/** * check_bindings: * @bhash:  * @thash:  * @bcounters:  *  * Check and remove expired bindings */voidcheck_bindings(struct bindingtable *bhash, struct hashtable *thash,	       struct binding_counters *bcounters){	static time_t prev_check;	static int first = 1;	struct bindingentry *binding;	static time_t advance_expire_time;	int diff;	time_t time_check;	time_t now;	time(&now);	if (first) {		time(&prev_check);		time(&advance_expire_time);		first = 0;	}	/* don't check too frequently */	if (now - prev_check < 1)		return;	prev_check = now;	time(&time_check);	diff = time_check - advance_expire_time;	advance_expire_time = time_check;	if (diff < 0) {		LOG2(LOG_WARNING,		     "check_bindings: diff(%i) < 0 - system time changed?\n",		     diff);		diff = 0;	}	binding = binding_getexpired(bhash, diff);	while (binding != NULL) {		struct tunnel_data *t_data;		struct exp_info_struct {			struct in_addr mn_addr;			struct in_addr ha_addr;		} exp_info;		t_data = (struct tunnel_data *) binding->data;		DEBUG(DEBUG_FLAG, "check_bindings: binding expired\n");		DEBUG(DEBUG_FLAG, "\tdiff = %d, expiretime = %d\n",		      diff, binding->timeout);		DEBUG(DEBUG_FLAG, "\tbinding->mn_addr = %s\n",		      inet_ntoa(binding->mn_addr));		DEBUG(DEBUG_FLAG, "\tbinding->lower_addr = %s\n",		      inet_ntoa(binding->lower_addr));		if (t_data->pending_request && t_data->unc_req != NULL) {			struct msg_extensions ext;			DEBUG(DEBUG_FLAG, "\tpending request timeout - "			      "informing MN\n");			memset(&ext, 0, sizeof(ext));			ext.req = &t_data->unc_req->req;			send_failure_reply(REGREP_REGISTRATION_TIMEOUT_FA,					   &ext, &t_data->unc_req->info, NULL,					   0);		}		exp_info.mn_addr = binding->mn_addr;		exp_info.ha_addr = binding->ha_addr;		remove_binding_tunnels(binding, thash, bcounters);		binding = binding_getexpired(bhash, 0);		info_send(FA_INFO_TIMEOUT, FA_INFO_OK, &exp_info,			  sizeof(exp_info));	}}/** * is_sender_mobile: * @ext:  *  * Determins if the sender of a request message is directly from a * mobile node based on the registration request extensions *  * Returns: 1 if the sender is a mobile, else 0 */intis_sender_mobile(struct msg_extensions *ext){	/* FIX: this should probably be replaced with	 * ext->ff_auth == NULL */	if (ext->fa_pubkey != NULL || ext->fa_keyreq != NULL)		return 0;	return 1;}/** * info_send: * @type:  * @status:  * @data:  * @len:  *  *  *  * Returns:  */intinfo_send(int type, int status, void *data, int len){	void *buf;	int n;	if (fa_info_sock < 0) return -1;	if (len > 0 && data == NULL) return -1;	buf = malloc(sizeof(type) + sizeof(status) + len);	if (buf == NULL) return -1;	memcpy(buf, &type, sizeof(type));	memcpy((char *)buf + sizeof(type), &status, sizeof(status));	if (len > 0)		memcpy((char *)buf + sizeof(type) + sizeof(status), data, len);	n = sendto(fa_info_sock, buf, sizeof(type) + sizeof(status) + len, 0,		   (struct sockaddr *) &fa_info_addr,		   sizeof(fa_info_addr.sun_family) +		   strlen(fa_info_addr.sun_path));	free(buf);	if (n < 0)		DEBUG(DEBUG_FLAG, "info_send: %s\n", strerror(errno));	return n;}/** * create_challenge_ext: * @config: pointer to FA configuration data * @type: extension type (AGENT_ADV_CHALLENGE_EXT / MN_FA_CHALLENGE_EXT) * * Create a new challenge extension. This function allocates memory for the * challenge and it is up to the caller to release the memory. *  * Returns: *   pointer to the created challenge or %NULL on failure */struct challenge_ext *create_challenge_ext(struct fa_config *config, int type){	int left;	struct challenge_ext *challenge;	__u32 *pos, tmp;	challenge = (struct challenge_ext *)		malloc(sizeof(struct challenge_ext) +		       config->challenge_length);	if (challenge == NULL) {		DEBUG(DEBUG_FLAG, "malloc for challenge_ext failed\n");		return NULL;	}	left = config->challenge_length;	challenge->type = type;	challenge->length = config->challenge_length;	pos = (__u32 *) MSG_CHALLENGE_EXT_DATA(challenge);	while (left >= 4) {		*pos++ = get_rand32();		left -= 4;	}	if (left > 0) {		tmp = get_rand32();		memcpy(pos, &tmp, left);	}	return challenge;}/** * equal_challenge: * @c1: pointer to challenge extension 1 (or %NULL) * @c2: pointer to challenge extension 2 (or %NULL) * * Compare two challenges and return 1 only if both exist and are equal in * length and contents. * * Returns: *   1 if @c1 and @c2 are equal challenges or 0 if not */int equal_challenge(struct challenge_ext *c1, struct challenge_ext *c2){	int len1, len2;	if (c1 == NULL || c2 == NULL)		return 0;	len1 = GET_CHALLENGE_LEN(c1);	len2 = GET_CHALLENGE_LEN(c2);	if (len1 != len2)		return 0;	if (memcmp(MSG_CHALLENGE_EXT_DATA(c1), MSG_CHALLENGE_EXT_DATA(c2),		   len1) == 0)		return 1;	return 0;}/** * setup_device_forcing: * @t_data: FA's binding data * * Setup device forcing for reverse tunneling. */void setup_device_forcing(struct tunnel_data *t_data){	/* When FA decapsulation is used with encapsulating delivery,	 * the down connection uses non-capsulated delivery to the MN,	 * but encapsulated delivery from the MN. */	if (t_data->fa_decapsulation && t_data->encaps_delivery)		memcpy(t_data->force_route_dev, t_data->info.iface->dev,		       IFNAMSIZ);	else		memset(t_data->force_route_dev, 0, IFNAMSIZ);	/* When MN decapsulation is used without encapsulating delivery,	 * the down connection uses encapsulated delivery to the MN,	 * but non-capsulated delivery from the MN. */	if (!t_data->fa_decapsulation && !t_data->encaps_delivery)		memcpy(t_data->force_reverse_dev, t_data->info.iface->dev,		       IFNAMSIZ);	else		memset(t_data->force_reverse_dev, 0, IFNAMSIZ);}/** * packet_socket_send: * @dst: L2 & L3 destination (from the original registration request) * @msg: message to be sent (UDP payload) * @len: length of the buffer (UDP payload) in bytes * * Send a registration reply using a packet and the destination learned from * the corresponding registration request. This function generates the IP and * UDP headers and instructs kernel to attach a suitable L2 header. * * Returns: * -1 on failure or number of sent bytes when successful */int packet_socket_send(struct packet_from_info *dst, const unsigned char *msg,		       int len){	unsigned char *buf;	struct iphdr *ip;	struct udphdr *udp;	int total_len, res;	total_len = len + sizeof(*ip) + sizeof(*udp);	buf = (unsigned char *) malloc(total_len);	if (buf == NULL) {		DEBUG(DEBUG_FLAG, "packet_socket_send: malloc failed\n");		return -1;	}	/* FIX: if packet is longer than MTU, it should be fragmented; since	 * the packet is send through a packet socket, the fragmentation is	 * left to us.. */	ip = (struct iphdr *) buf;	memset(ip, 0, sizeof(*ip));	ip->ihl = 5;	ip->version = 4;	ip->ttl = 255;	ip->protocol = IPPROTO_UDP;	ip->daddr = dst->src.sin_addr.s_addr;	ip->saddr = dst->dst_addr.s_addr;	ip->tot_len = htons(total_len);	ip->check = 0;	ip->check = ip_checksum(buf, sizeof(*ip));	udp = (struct udphdr *) (ip + 1);	udp->source = htons(434);	udp->dest = dst->src.sin_port;	udp->len = htons(sizeof(*udp) + len);	memcpy(udp + 1, msg, len);	udp->check = 0;	udp->check = udp_checksum(ip, udp);	res = sendto(dst->iface->udp_packet, buf, total_len, 0,		     (struct sockaddr *) &dst->from, sizeof(dst->from));	free(buf);	if (res < 0)		return res;	return res - sizeof(*ip) - sizeof(*udp);}

⌨️ 快捷键说明

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