secgateway/Platform/user/configm/config-server/netconfig/ifconfig.c

654 lines
15 KiB
C

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include "rpc.h"
#include "netconfig.h"
#include "parsefile.h"
#ifndef _LINUX_IN6_H
/*
* This is in linux/include/net/ipv6.h.
*/
struct in6_ifreq {
struct in6_addr ifr6_addr;
uint ifr6_prefixlen;
unsigned int ifr6_ifindex;
};
#endif
net_ifnum_t g_if_num = {.wan_num = 2, .lan_num = 4};
/* Display an Ethernet address in readable format. */
static void print_ether(char *buff, unsigned char *ptr)
{
snprintf(buff, 32, "%02X:%02X:%02X:%02X:%02X:%02X",
(ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
(ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
);
}
#if 0
static uint ethtool_cmd_speed(const struct ethtool_cmd *ep)
{
return (ep->speed_hi << 16) | ep->speed;
}
#endif
/* call ioctl system call */
ret_code if_ioctl(int af, unsigned long request, caddr_t ifreq)
{
int sock;
int err = 0;
sock = socket(af, SOCK_DGRAM, 0);
if (sock < 0)
{
rpc_log_error("Cannot create UDP socket");
return RET_SYSERR;
}
if ((err = ioctl(sock, request, ifreq)) < 0)
{
rpc_log_error("Ioctl error: %s\n", strerror(errno));
}
close(sock);
if (err < 0)
{
return RET_SYSERR;
}
return RET_OK;
}
/* call ioctl system call */
ret_code if_ethctl(char *name, void *cmd)
{
struct ifreq ifr = {0};
int sock;
int err = 0;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
{
rpc_log_error("Cannot create UDP socket");
return RET_SYSERR;
}
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name) - 1);
ifr.ifr_data = cmd;
if ((err = ioctl(sock, SIOCETHTOOL, &ifr)) < 0)
{
rpc_log_error("Ioctl error: %s\n", strerror(errno));
}
close(sock);
if (err < 0)
{
return RET_SYSERR;
}
return RET_OK;
}
ret_code if_get_ipenable(if_info_t *if_info)
{
if(strcmp(if_info->ifname, "lo") == 0)
{
strcpy(if_info->ipenable, "false");
return RET_OK;
}
if(br_if_bridge_get(if_info->ifname, NULL) == RET_OK)
{
strcpy(if_info->ipenable, "false");
return RET_OK;
}
strcpy(if_info->ipenable, "true");
return RET_OK;
}
ret_code if_get_v4proto(if_info_t *if_info)
{
char iface[IF_BUFF_LEN] = {0};
char protostr[IF_BUFF_LEN] = {0};
sprintf(iface, "iface %s inet", if_info->ifname);
if_conf_file_get(if_info->ifname, iface, protostr);
if(strstr(protostr, "dhcp"))
{
strcpy(if_info->v4protocol, "dhcp");
}
else
{
strcpy(if_info->v4protocol, "static");
}
return RET_OK;
}
ret_code if_get_v6proto(if_info_t *if_info)
{
char iface[IF_BUFF_LEN] = {0};
char protostr[IF_BUFF_LEN] = {0};
sprintf(iface, "iface %s inet6", if_info->ifname);
if_conf_file_get(if_info->ifname, iface, protostr);
if(strstr(protostr, "dhcp"))
{
strcpy(if_info->v6protocol, "dhcp");
}
else
{
strcpy(if_info->v6protocol, "static");
}
return RET_OK;
}
ret_code if_get_linksetting(if_info_t *if_info)
{
ret_code ret = RET_OK;
struct ethtool_link_data ecmd;
unsigned int u32_offs;
/* Handshake with kernel to determine number of words for link
* mode bitmaps. When requested number of bitmap words is not
* the one expected by kernel, the latter returns the integer
* opposite of what it is expecting. We request length 0 below
* (aka. invalid bitmap length) to get this info.
*/
memset(&ecmd, 0, sizeof(ecmd));
ecmd.req.cmd = ETHTOOL_GLINKSETTINGS;
ret = if_ethctl(if_info->ifname, &ecmd);
ASSERT_RET(ret);
/* see above: we expect a strictly negative value from kernel.
*/
ASSERT_COND(ecmd.req.link_mode_masks_nwords >= 0
|| ecmd.req.cmd != ETHTOOL_GLINKSETTINGS);
/* got the real ecmd.req.link_mode_masks_nwords,
* now send the real request
*/
ecmd.req.cmd = ETHTOOL_GLINKSETTINGS;
ecmd.req.link_mode_masks_nwords = -ecmd.req.link_mode_masks_nwords;
ret = if_ethctl(if_info->ifname, &ecmd);
ASSERT_RET(ret);
ASSERT_COND(ecmd.req.link_mode_masks_nwords <= 0
|| ecmd.req.cmd != ETHTOOL_GLINKSETTINGS);
sprintf(if_info->maxspeed, "%uMb/s", ecmd.req.speed);
return ret;
}
ret_code if_get_setting(if_info_t *if_info)
{
ret_code ret = RET_OK;
struct ethtool_cmd ecmd;
memset(&ecmd, 0, sizeof(ecmd));
ecmd.cmd = ETHTOOL_GSET;
ret = if_ethctl(if_info->ifname, &ecmd);
ASSERT_RET(ret);
sprintf(if_info->maxspeed, "%uMb/s", ethtool_cmd_speed(&ecmd));
return ret;
}
ret_code if_get_linkstat(if_info_t *if_info)
{
struct ethtool_value edata = {0};
ret_code ret = RET_OK;
edata.cmd = ETHTOOL_GLINK;
ret = if_ethctl(if_info->ifname, &edata);
ASSERT_RET(ret);
if(edata.data)
{
strcpy(if_info->state, "up");
}
else
{
strcpy(if_info->state, "down");
}
return ret;
}
ret_code if_get_maxspeed(if_info_t *if_info)
{
ret_code ret = RET_OK;
ret = if_get_linksetting(if_info);
if(ret != RET_OK)
{
ret = if_get_setting(if_info);
}
ASSERT_RET(ret);
return ret;
}
ret_code if_get_hwaddr(if_info_t *if_info)
{
struct ifreq ifr = {0};
ret_code ret = RET_OK;
if_role_file_get(if_info->ifname, if_info->role, INTERFACE_NAMSIZ);
strncpy(ifr.ifr_name, if_info->ifname, sizeof(ifr.ifr_name) - 1);
ret = if_ioctl(AF_INET, SIOCGIFHWADDR, (caddr_t)&ifr);
ASSERT_RET(ret);
print_ether(if_info->hwaddr, ifr.ifr_hwaddr.sa_data);
return ret;
}
/* Set a certain interface flag. */
static int if_set_flag(char *ifname, short flag)
{
struct ifreq ifr = {0};
ret_code ret = RET_OK;
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
ret = if_ioctl(AF_INET, SIOCGIFFLAGS, (caddr_t)&ifr);
ASSERT_RET(ret);
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
ifr.ifr_flags |= flag;
ret = if_ioctl(AF_INET, SIOCSIFFLAGS, (caddr_t)&ifr);
ASSERT_RET(ret);
return ret;
}
/* Clear a certain interface flag. */
static int if_clear_flag(char *ifname, short flag)
{
struct ifreq ifr = {0};
ret_code ret;
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
ret = if_ioctl(AF_INET, SIOCGIFFLAGS, (caddr_t)&ifr);
ASSERT_RET(ret);
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
ifr.ifr_flags &= ~flag;
ret = if_ioctl(AF_INET, SIOCSIFFLAGS, (caddr_t)&ifr);
ASSERT_RET(ret);
return ret;
}
ret_code if_set_up(char *ifname)
{
return if_set_flag(ifname, (IFF_UP | IFF_RUNNING));
}
ret_code if_set_down(char *ifname)
{
return if_clear_flag(ifname, IFF_UP);
}
int if_get_allport(struct ifreq *ifreq, int max_port)
{
ret_code ret = RET_OK;
struct ifconf ifc;
int if_count;
if_count = if_read_dev_file(ifreq, max_port);
if(if_count == 0)
{
memset(&ifc, 0, sizeof(struct ifconf));
ifc.ifc_len = max_port * sizeof(struct ifreq);
ifc.ifc_buf = (char *)ifreq;
ret = if_ioctl(AF_INET, SIOCGIFCONF, (caddr_t)&ifc);
ASSERT_RET(ret);
if_count = ifc.ifc_len / (sizeof(struct ifreq));
}
return if_count;
}
ret_code if_set_prefix(ip_config_t *ip_conf)
{
ret_code ret;
struct ifreq ifreq = {0};
struct sockaddr_in addr;
struct sockaddr_in mask;
if_info_t if_info = {0};
strncpy(ifreq.ifr_name, ip_conf->ifname, sizeof(ifreq.ifr_name) - 1);
addr.sin_addr = ip_conf->ipv4.addr;
addr.sin_family = ip_conf->family;
memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in));
if(ip_conf->ipv4.addr.s_addr == 0)
{
strcpy(if_info.ifname, ip_conf->ifname);
if_get_v4proto(&if_info);
if(strcmp(if_info.v4protocol, "dhcp") == 0)
{
ret = RET_NOTSUPPORT;
ASSERT_RET(ret);
}
}
ret = if_ioctl(AF_INET, SIOCSIFADDR, (caddr_t)&ifreq);
ASSERT_RET(ret);
if(ip_conf->ipv4.addr.s_addr != 0)
{
mask.sin_addr = ip_conf->ipv4.mask;
mask.sin_family = ip_conf->family;
memcpy(&ifreq.ifr_netmask, &mask, sizeof(struct sockaddr_in));
ret = if_ioctl(AF_INET, SIOCSIFNETMASK, (caddr_t)&ifreq);
ASSERT_RET(ret);
}
return RET_OK;
}
ret_code if_del_oldin6(char *name, struct in6_ifreq *ifr6)
{
v6addr_t ipv6_arr[IPV6_ADDR_NUM] = {0};
struct in6_ifreq ifdel = {0};
ret_code ret = RET_OK;
int addr_cnt = 0;
int i;
addr_cnt = if_read_in6_file(name, ipv6_arr, IPV6_ADDR_NUM);
for(i = 0; i < addr_cnt; i++)
{
if(IPV6_ADDR_CMP(&(ifr6->ifr6_addr), &(ipv6_arr[i].addr)) == 0
&& ifr6->ifr6_prefixlen == ipv6_arr[i].prefixlen)
{
ret = RET_EXIST;
continue;
}
memset(&ifdel, 0, sizeof(struct in6_ifreq));
ifdel.ifr6_ifindex = ifr6->ifr6_ifindex;
ifdel.ifr6_prefixlen = ipv6_arr[i].prefixlen;
memcpy((char *) &ifdel.ifr6_addr, &(ipv6_arr[i].addr), sizeof(struct in6_addr));
if_ioctl(AF_INET6, SIOCDIFADDR, (caddr_t)&ifdel);
}
return ret;
}
ret_code if_set_prefix6(uint config_type, ip_config_t *ip_conf)
{
ret_code ret = RET_OK;
struct ifreq ifr = {0};
struct in6_ifreq ifr6 = {0};
if_info_t if_info = {0};
uint ifindex;
strncpy(ifr.ifr_name, ip_conf->ifname, sizeof(ifr.ifr_name) - 1);
ret = if_ioctl(AF_INET, SIOGIFINDEX, (caddr_t)&ifr);
ASSERT_RET(ret);
ifr6.ifr6_ifindex = ifr.ifr_ifindex;
ifr6.ifr6_prefixlen = ip_conf->ipv6.prefixlen;
memcpy((char *) &ifr6.ifr6_addr, &(ip_conf->ipv6.addr), sizeof(struct in6_addr));
if(config_type == CM_CONFIG_SET)
{
ret = if_del_oldin6(ip_conf->ifname, &ifr6);
if(ret == RET_EXIST)
{
return RET_OK;
}
ret = if_ioctl(AF_INET6, SIOCSIFADDR, (caddr_t)&ifr6);
}
else if(config_type == CM_CONFIG_DEL)
{
strcpy(if_info.ifname, ip_conf->ifname);
if_get_v6proto(&if_info);
if(strcmp(if_info.v6protocol, "dhcp") == 0)
{
ret = RET_NOTSUPPORT;
ASSERT_RET(ret);
}
ret = if_ioctl(AF_INET6, SIOCDIFADDR, (caddr_t)&ifr6);
}
ASSERT_RET(ret);
return RET_OK;
}
ret_code if_get_prefix(if_info_t *if_conf)
{
struct sockaddr_in *sockaddr;
struct ifreq ifreq;
ret_code ret = RET_OK;
memset(&ifreq, 0, sizeof(struct ifreq));
rpc_log_info("get interface %s info\n", if_conf->ifname);
/* get ip address */
strncpy(ifreq.ifr_name, if_conf->ifname, sizeof(ifreq.ifr_name) - 1);
ret = if_ioctl(AF_INET, SIOCGIFADDR, (caddr_t)&ifreq);
ASSERT_RET(ret);
sockaddr = (struct sockaddr_in *)&(ifreq.ifr_addr);
strcpy(if_conf->ipv4.addr, inet_ntoa(sockaddr->sin_addr));
/* get ip netmask */
memset(&ifreq, 0, sizeof(ifreq));
strncpy(ifreq.ifr_name, if_conf->ifname, sizeof(ifreq.ifr_name) - 1);
ret = if_ioctl(AF_INET, SIOCGIFNETMASK, (caddr_t)&ifreq);
ASSERT_RET_NO(ret);
sockaddr = (struct sockaddr_in *)&(ifreq.ifr_netmask);
strcpy(if_conf->ipv4.prefixlen, inet_ntoa(sockaddr->sin_addr));
return ret;
}
int if_get_prefix6(if_info_t *if_conf)
{
v6addr_t ipv6_arr[IPV6_ADDR_NUM];
int addr_cnt = 0;
int i;
addr_cnt = if_read_in6_file(if_conf->ifname, ipv6_arr, IPV6_ADDR_NUM);
for(i = 0; i < addr_cnt && i < IPV6_ADDR_NUM; i++)
{
inet_ntop(AF_INET6, &ipv6_arr[i].addr, if_conf->ipv6[i].addr, DOT_IPV6_STR);
snprintf(if_conf->ipv6[i].prefixlen, IF_INFO_STR, "%d", ipv6_arr[i].prefixlen);
}
return i;
}
int if_lan_num()
{
return g_if_num.lan_num;
}
int if_wan_num()
{
return g_if_num.wan_num;
}
ret_code if_num_init()
{
char role_str[IF_BUFF_LEN] = {0};
struct ifreq ifreq[MAX_IF_NUM];
int if_count = 0;
int lan_count = 0;
int wan_count = 0;
int i;
/*char ifname[MAX_IF_NUM][INTERFACE_NAMSIZ];*/
memset(&ifreq, 0, MAX_IF_NUM * sizeof(struct ifreq));
if_count = if_read_dev_file(ifreq, MAX_IF_NUM);
for(i = 0; i < if_count; i++)
{
memset(role_str, 0, IF_BUFF_LEN);
if(if_role_file_get(ifreq[i].ifr_name, role_str, IF_BUFF_LEN) != RET_OK)
{
continue;
}
if(strcasecmp(role_str, "lan"))
{
lan_count++;
}
else if(strcasecmp(role_str, "wan"))
{
wan_count++;
}
}
if(lan_count != 0)
{
g_if_num.lan_num = lan_count;
}
if(wan_count != 0)
{
g_if_num.wan_num = wan_count;
}
/*memset(ifname, 0, sizeof(ifname));
wan_count = if_wan_get(ifname, MAX_IF_NUM);
printf("wan get cnt %d\n", wan_count);
for(i = 0; i < wan_count; i++)
{
printf("interface %s\n", ifname[i]);
}*/
return RET_OK;
}
int if_wan_get(char ifname[MAX_IF_NUM][INTERFACE_NAMSIZ], int max_port)
{
char role_str[IF_BUFF_LEN] = {0};
struct ifreq ifreq[MAX_IF_NUM];
int if_count = 0;
int wan_count = 0;
int i;
memset(&ifreq, 0, MAX_IF_NUM * sizeof(struct ifreq));
if_count = if_read_dev_file(ifreq, MAX_IF_NUM);
for(i = 0; i < if_count; i++)
{
memset(role_str, 0, IF_BUFF_LEN);
if(if_role_file_get(ifreq[i].ifr_name, role_str, IF_BUFF_LEN) != RET_OK)
{
continue;
}
if(wan_count >= max_port)
{
break;
}
if(strcasecmp(role_str, "wan"))
{
strncpy(ifname[wan_count], ifreq[i].ifr_name, INTERFACE_NAMSIZ - 1);
wan_count++;
}
}
return wan_count;
}
int if_lan_get(char ifname[MAX_IF_NUM][INTERFACE_NAMSIZ], int max_port)
{
char role_str[IF_BUFF_LEN] = {0};
struct ifreq ifreq[MAX_IF_NUM];
int if_count = 0;
int lan_count = 0;
int i;
memset(&ifreq, 0, MAX_IF_NUM * sizeof(struct ifreq));
if_count = if_read_dev_file(ifreq, MAX_IF_NUM);
for(i = 0; i < if_count; i++)
{
memset(role_str, 0, IF_BUFF_LEN);
if(if_role_file_get(ifreq[i].ifr_name, role_str, IF_BUFF_LEN) != RET_OK)
{
continue;
}
if(lan_count >= max_port)
{
break;
}
if(strcasecmp(role_str, "lan"))
{
strncpy(ifname[lan_count], ifreq[i].ifr_name, INTERFACE_NAMSIZ - 1);
lan_count++;
}
}
return lan_count;
}