📄 mn_api.c
字号:
/* $Id: mn_api.c,v 1.46 2001/09/29 16:06:39 jm Exp $ * Mobile Node - API handling * * 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. */#include "config.h"#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <errno.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <time.h>#include "agentapi.h"#include "debug.h"#include "dyn_ip.h"#include "list.h"#include "util.h"#ifdef WITH_WIRELESS#include "monitor.h"#endif#include "mn.h"extern struct mn_data mn;extern struct mn_config config; /* configuration information */extern struct timeval timers[TIMER_COUNT];/* Policies can be changed on/off from dynmn_tool (policy) */static struct policy_vars monitor_policy[] = { {EARLY_EXPIRE_STR, EARLY_EXPIRE_BIT}, {NEWEST_FA_STR, NEWEST_FA_BIT}, {EAGER_SWITCH_STR, EAGER_SWITCH_BIT}, {NEWEST_ADV_STR, NEWEST_ADV_BIT}, {"", -1}};static dyn_api_sockaddr api_addr; /* address of progressing api call */static socklen_t api_addr_len = 0;/* String representations of the states */char *state_strings[MN_STATE_COUNT] = { "Startup", "Disconnected", "Find Agent", "Passive Find", "Request Tunnel", "Connected", "Close For Home", "At Home", "Error", "Stop" };/* Fill static status structure and return a pointer to it. */static struct dynamics_mobile_status *get_mobile_status(void){ static struct dynamics_mobile_status status; status.state = mn.state; if (mn.state >= 0 && mn.state < MN_STATE_COUNT) dynamics_strlcpy(status.state_str, state_strings[mn.state], API_STATE_LEN); else memset(status.state_str, 0, sizeof(status.state_str)); status.local_addr = mn.local_addr; status.co_addr = mn.co_addr; status.fa_addr = mn.fa_addr; status.ha_addr = config.ha_ip_addr; status.home_addr = config.mn_home_ip_addr; status.tunnel_up = mn.tunnel_up; status.tunnel_mode = mn.tunnel_mode; if (mn.tunnel_up) { status.lifetime = timers[TIMER_LIFETIME].tv_sec - time(NULL); } else { status.lifetime = 0; } status.last_reply_code = mn.last_reply_code; status.last_reply_rcvd = mn.last_reply_rcvd; status.last_request_sent = mn.last_request_sent; if (mn.info_str == NULL) memset(status.info_str, 0, API_INFO_LEN + 1); else dynamics_strlcpy(status.info_str, mn.info_str, API_INFO_LEN + 1); if (mn.warn_str == NULL) memset(status.warn_str, 0, API_INFO_LEN + 1); else dynamics_strlcpy(status.warn_str, mn.warn_str, API_INFO_LEN + 1); status.device_count = mn.device_count; status.discarded_msgs = mn.discarded_msgs; return &status;}/* * Handling function for API update location call. API message is in msg. * Set own local address according to msg. If in disconnected state, stay * there, but otherwise go to find_agent state, because we have * moved under another FA and we will want hear its address. * Tunnels must be updated for new address. */static void handle_api_locupd(int s, dyn_api_sockaddr *addr, socklen_t addrlen, struct api_msg *msg, int block_api){ int ok, i; char device[IFNAMSIZ + 1]; struct in_addr iaddr; /* locupd should have new IP address or interface name after four * zero octets */ ok = 1; if (msg->length == 4) { if (mn.local_addr.s_addr != (__u32) *msg->params) { /* set local address */ memcpy(&mn.local_addr, msg->params, 4); DEBUG(DEBUG_INFO, "Address changed to %s\n", inet_ntoa(mn.local_addr)); } } else if (msg->length > 4 && msg->params[0] == 0 && msg->params[1] == 0 && msg->params[2] == 0 && msg->params[3] == 0) { if (msg->length > IFNAMSIZ) ok = 0; else { memcpy(device, msg->params + 4, msg->length - 4); device[msg->length - 4] = '\0'; ok = 2; } } else if (msg->length == 0) { /* try to use the first available interface */ for (i = 0; i < MAX_INTERFACES; i++) { if (mn.iface[i].s > -1) { memcpy(device, mn.iface[i].device, IFNAMSIZ); device[sizeof(device) - 1] = '\0'; ok = 2; break; } } if (ok != 2) ok = 0; } else ok = 0; if (ok == 2) { DEBUG(DEBUG_INFO, "\tinterface[%s]\n", device); if (dyn_ip_get_ifaddr(device, &iaddr) < 0) ok = 0; else if (mn.local_addr.s_addr != iaddr.s_addr) { DEBUG(DEBUG_INFO, "Address changed to %s (%s)\n", inet_ntoa(iaddr), device); mn.local_addr.s_addr = iaddr.s_addr; } } if (!ok) { DEBUG(DEBUG_INFO, "API: locupd failed - illegal parameter\n"); api_send_reply(s, addr, addrlen, API_ILLEGAL_PARAMETERS, NULL, 0); return; } /* check if we are at home */ if (mn.local_addr.s_addr == config.mn_home_ip_addr.s_addr && !config.enable_fa_decapsulation) { close_for_home(STATE_INIT); } else { switch (mn.state) { case MN_DISCONNECTED: break; default: /* allow quick locupd */ timerclear(&mn.last_reg_send_time); find_agent(STATE_INIT); break; } } if (!block_api) api_send_reply(s, addr, addrlen, API_SUCCESS, NULL, 0);}static void handle_api_force_fa(int s, dyn_api_sockaddr *addr, socklen_t addrlen, struct api_msg *msg){ /* force_fa should have new address */ if (msg->length != 4) { api_send_reply(s, addr, addrlen, API_ILLEGAL_PARAMETERS, NULL, 0); return; } /* set local address */ memcpy(&mn.force_fa_addr, msg->params, 4); DEBUG(DEBUG_INFO, "Force FA address set to %s\n", inet_ntoa(mn.force_fa_addr)); api_send_reply(s, addr, addrlen, API_SUCCESS, NULL, 0);}static int adv_iter(struct node *node, void *data){ struct agentadv_data *adv; struct api_msg *api_msg; struct dynamics_mobile_fa_list *list; int size, tmp; unsigned int flags; adv = (struct agentadv_data *) node; api_msg = (struct api_msg *) data; list = (struct dynamics_mobile_fa_list *) ((char *) api_msg->params + api_msg->length); size = sizeof(struct dynamics_mobile_fa_list); if ((api_msg->length + size) > API_DATA_SIZE) { DEBUG(DEBUG_INFO, "adv_iter: Not enough room in msg " " (itemsize %d, length %d)\n", size, api_msg->length); return 0; } api_msg->length += size; /* copy values */ UNALIGNED_(&list->addr, &adv->addr); MOVE_UNALIGNED(list->interface, adv->ifname, IFNAMSIZ); UNALIGNED_(&list->in_use, &adv->in_use); if (mn.current_adv != NULL && adv->addr.s_addr == mn.current_adv->addr.s_addr) { tmp = 1; } else { tmp = 0; } UNALIGNED_(&list->current_adv, &tmp); flags = 0; if (adv->adv.ext) { int opts = ntohs(adv->adv.ext->opts); if (opts & AGENT_ADV_FOREIGN_AGENT) flags |= API_MA_FLAGS_FA; if (opts & AGENT_ADV_HOME_AGENT) flags |= API_MA_FLAGS_HA; if (opts & AGENT_ADV_BUSY) flags |= API_MA_FLAGS_BUSY; } if (adv->adv.own_ext) flags |= API_MA_FLAGS_DYNAMICS; UNALIGNED_(&list->flags, &flags);#ifdef WITH_WIRELESS if (adv->mon != NULL) { tmp = adv->mon->avg; } else { tmp = -1; }#else tmp = -1;#endif UNALIGNED_(&list->quality_avg, &tmp); /* Priorities aren't calculated if MN is in DISCONNECTED state. That is why we don't want to update priority because it's not up to date information and may confuse the user. */ if (mn.state == MN_DISCONNECTED) { tmp = -2; /* not up to date information */ UNALIGNED_(&list->priority, &tmp); } else UNALIGNED_(&list->priority, &adv->priority); UNALIGNED_(&list->last, &adv->last.tv_sec); UNALIGNED_(&list->reduce, &adv->prio_degrade_percent); return 1;}static void handle_api_get_fa_list(int s, dyn_api_sockaddr *addr, socklen_t addrlen, struct api_msg *msg){ msg->length = 0; hashtable_iterator(mn.agentadv, adv_iter, msg); api_send_reply(s, addr, addrlen, API_SUCCESS, (unsigned char *) &msg->params, msg->length);}static void handle_api_get_fa_info(int s, dyn_api_sockaddr *addr, socklen_t addrlen, struct api_msg *msg){ struct dynamics_mobile_fa_info *info; struct agentadv_data *adv; struct in_addr fa_addr; int ifindex, tmp; char interface[IFNAMSIZ + 1]; char nai[API_MAX_NAI_LEN + 1]; /* should have fa address */ if (msg->length != sizeof(struct dynamics_mobile_fa_info)) { api_send_reply(s, addr, addrlen, API_ILLEGAL_PARAMETERS, NULL, 0); return; } info = (struct dynamics_mobile_fa_info *)&msg->params; MOVE_UNALIGNED(&fa_addr, &info->list.addr, sizeof(struct in_addr)); DEBUG(DEBUG_API, "handle_api_get_fa_info: %s\n", inet_ntoa(fa_addr)); ifindex = 0; MOVE_UNALIGNED(interface, &info->list.interface, IFNAMSIZ); interface[IFNAMSIZ] = '\0'; if (strlen(interface) > 0) { ifindex = dyn_ip_get_ifindex(interface); DEBUG(DEBUG_API, "handle_api_get_fa_info: interface \"%s\"" " ifindex %d\n", interface, ifindex); } adv = adv_fetch(mn.agentadv, &fa_addr, ifindex); if (adv == NULL) { DEBUG(DEBUG_API, "handle_api_get_fa_info: %s not found\n", inet_ntoa(fa_addr)); api_send_reply(s, addr, addrlen, API_FAILED, NULL, 0); return; } msg->length = sizeof(struct dynamics_mobile_fa_info); UNALIGNED_(&info->list.addr, &adv->addr); UNALIGNED_(&info->list.in_use, &adv->in_use); UNALIGNED_(&info->ifindex, &ifindex);#ifdef WITH_WIRELESS if (adv->mon != NULL) UNALIGNED_(&info->list.quality_avg, &adv->mon->avg); else { tmp = -1; UNALIGNED_(&info->list.quality_avg, &tmp); }#else tmp = -1; UNALIGNED_(&info->list.quality_avg, &tmp);#endif UNALIGNED_(&tmp, &info->list.quality_avg); DEBUG(DEBUG_INFO, "quality: %d\n", tmp); UNALIGNED_(&info->list.priority, &adv->priority); UNALIGNED_(&info->ifindex, &adv->ifindex); MOVE_UNALIGNED(info->list.interface, adv->ifname, sizeof(adv->ifname)); UNALIGNED_(&info->list.last, &adv->last.tv_sec); UNALIGNED_(&info->expire, &adv->expire.tv_sec); UNALIGNED_(&info->arpentry, &adv->arpentry); nai[0] = '\0'; if (adv->adv.fa_nai != NULL && API_MAX_NAI_LEN >= GET_NAI_LEN(adv->adv.fa_nai)) { memcpy(nai, MSG_NAI_DATA(adv->adv.fa_nai), API_MAX_NAI_LEN); nai[GET_NAI_LEN(adv->adv.fa_nai)] = '\0'; } DEBUG(DEBUG_INFO, "\tNAI[%s]\n", nai); MOVE_UNALIGNED(&info->nai, &nai, API_MAX_NAI_LEN + 1); api_send_reply(s, addr, addrlen, API_SUCCESS, (unsigned char *) &msg->params, msg->length);}#ifdef WITH_WIRELESSstatic void handle_api_get_iw_ch(int s, dyn_api_sockaddr *addr, socklen_t addrlen, struct api_msg *msg){ int r;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -