581 lines
13 KiB
C
581 lines
13 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 *ret)
|
|
{
|
|
int sock;
|
|
int err = 0;
|
|
|
|
if(ret)
|
|
{
|
|
*ret = 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)
|
|
{
|
|
if(ret)
|
|
{
|
|
*ret = err;
|
|
}
|
|
return RET_SYSERR;
|
|
}
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
/* call ioctl system call */
|
|
ret_code if_ethctl(char *name, void *cmd, int *ret)
|
|
{
|
|
struct ifreq ifr = {0};
|
|
int sock;
|
|
int err = 0;
|
|
|
|
if(ret)
|
|
{
|
|
*ret = 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)
|
|
{
|
|
if(ret)
|
|
{
|
|
*ret = err;
|
|
}
|
|
return RET_SYSERR;
|
|
}
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
ret_code if_get_linksetting(if_info_t *if_info, int *code)
|
|
{
|
|
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, code);
|
|
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, code);
|
|
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, int *code)
|
|
{
|
|
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, code);
|
|
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, int *code)
|
|
{
|
|
struct ethtool_value edata = {0};
|
|
ret_code ret = RET_OK;
|
|
|
|
edata.cmd = ETHTOOL_GLINK;
|
|
ret = if_ethctl(if_info->ifname, &edata, code);
|
|
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, int *code)
|
|
{
|
|
ret_code ret = RET_OK;
|
|
|
|
ret = if_get_linksetting(if_info, code);
|
|
if(ret != RET_OK)
|
|
{
|
|
ret = if_get_setting(if_info, code);
|
|
}
|
|
|
|
ASSERT_RET(ret);
|
|
return ret;
|
|
}
|
|
|
|
ret_code if_get_hwaddr(if_info_t *if_info, int *code)
|
|
{
|
|
struct ifreq ifr = {0};
|
|
ret_code ret = RET_OK;
|
|
|
|
strncpy(ifr.ifr_name, if_info->ifname, sizeof(ifr.ifr_name) - 1);
|
|
|
|
ret = if_ioctl(AF_INET, SIOCGIFHWADDR, (caddr_t)&ifr, code);
|
|
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, int *code)
|
|
{
|
|
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, code);
|
|
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, code);
|
|
ASSERT_RET(ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Clear a certain interface flag. */
|
|
static int if_clear_flag(char *ifname, short flag, int *code)
|
|
{
|
|
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, code);
|
|
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, code);
|
|
ASSERT_RET(ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
ret_code if_set_up(char *ifname, int *code)
|
|
{
|
|
return if_set_flag(ifname, (IFF_UP | IFF_RUNNING), code);
|
|
}
|
|
|
|
ret_code if_set_down(char *ifname, int *code)
|
|
{
|
|
return if_clear_flag(ifname, IFF_UP, code);
|
|
}
|
|
|
|
int if_get_allport(struct ifreq *ifreq, int max_port)
|
|
{
|
|
ret_code ret = RET_OK;
|
|
struct ifconf ifc;
|
|
int if_count;
|
|
int code;
|
|
|
|
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, &code);
|
|
ASSERT_RET(ret);
|
|
|
|
if_count = ifc.ifc_len / (sizeof(struct ifreq));
|
|
}
|
|
|
|
return if_count;
|
|
}
|
|
|
|
ret_code if_set_prefix(ip_config_t *ip_conf, int *code)
|
|
{
|
|
ret_code ret;
|
|
struct ifreq ifreq = {0};
|
|
struct sockaddr_in addr;
|
|
struct sockaddr_in mask;
|
|
|
|
strncpy(ifreq.ifr_name, ip_conf->ifname, sizeof(ifreq.ifr_name) - 1);
|
|
addr.sin_addr = ip_conf->prefix;
|
|
addr.sin_family = ip_conf->family;
|
|
memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in));
|
|
|
|
ret = if_ioctl(AF_INET, SIOCSIFADDR, (caddr_t)&ifreq, code);
|
|
ASSERT_RET(ret);
|
|
|
|
if(ip_conf->prefix.s_addr != 0)
|
|
{
|
|
masklen2ip(ip_conf->prefixlen, &mask.sin_addr);
|
|
mask.sin_family = ip_conf->family;
|
|
memcpy(&ifreq.ifr_netmask, &mask, sizeof(struct sockaddr_in));
|
|
|
|
ret = if_ioctl(AF_INET, SIOCSIFNETMASK, (caddr_t)&ifreq, code);
|
|
ASSERT_RET(ret);
|
|
}
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
ret_code if_set_prefix6(uint config_type, ip_config_t *ip_conf, int *code)
|
|
{
|
|
ret_code ret = RET_OK;
|
|
struct ifreq ifr = {0};
|
|
struct in6_ifreq ifr6 = {0};
|
|
|
|
strncpy(ifr.ifr_name, ip_conf->ifname, sizeof(ifr.ifr_name) - 1);
|
|
|
|
ret = if_ioctl(AF_INET, SIOGIFINDEX, (caddr_t)&ifr, code);
|
|
ASSERT_RET(ret);
|
|
|
|
ifr6.ifr6_ifindex = ifr.ifr_ifindex;
|
|
ifr6.ifr6_prefixlen = ip_conf->prefixlen;
|
|
|
|
memcpy((char *) &ifr6.ifr6_addr, &(ip_conf->prefix6), sizeof(struct in6_addr));
|
|
|
|
if(config_type == CM_CONFIG_SET)
|
|
{
|
|
ret = if_ioctl(AF_INET6, SIOCSIFADDR, (caddr_t)&ifr6, code);
|
|
}
|
|
else if(config_type == CM_CONFIG_DEL)
|
|
{
|
|
ret = if_ioctl(AF_INET6, SIOCDIFADDR, (caddr_t)&ifr6, code);
|
|
}
|
|
|
|
ASSERT_RET(ret);
|
|
|
|
return RET_OK;
|
|
}
|
|
|
|
ret_code if_get_prefix(if_info_t *if_conf, int *code)
|
|
{
|
|
struct sockaddr_in *addr;
|
|
struct ifreq ifreq;
|
|
ret_code ret = RET_OK;
|
|
int mask_ret;
|
|
|
|
memset(&ifreq, 0, sizeof(struct ifreq));
|
|
|
|
rpc_log_info("get interface %s info\n", if_conf->ifname);
|
|
|
|
strncpy(ifreq.ifr_name, if_conf->ifname, sizeof(ifreq.ifr_name) - 1);
|
|
|
|
ret = if_ioctl(AF_INET, SIOCGIFADDR, (caddr_t)&ifreq, code);
|
|
ASSERT_RET(ret);
|
|
|
|
strcpy(if_conf->ipv4.addr, inet_ntoa(((struct sockaddr_in *)&(ifreq.ifr_addr))->sin_addr));
|
|
|
|
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, &mask_ret);
|
|
ASSERT_RET_NO(ret);
|
|
|
|
addr = ( struct sockaddr_in * )&(ifreq.ifr_netmask);
|
|
if_conf->ipv4.prefixlen = ip_masklen(addr->sin_addr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if 0
|
|
ret_code if_get_prefix6(if_info_t *if_conf, int *code)
|
|
{
|
|
FILE *f;
|
|
char addr6[40], devname[20];
|
|
struct sockaddr_in6 sap;
|
|
int plen, scope, dad_status, if_idx;
|
|
char addr6p[8][5];
|
|
|
|
/* FIXME: should be integrated into interface.c. */
|
|
|
|
if ((f = fopen(PROC_NET_IFINET6, "r")) != NULL) {
|
|
while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
|
|
addr6p[0], addr6p[1], addr6p[2], addr6p[3],
|
|
addr6p[4], addr6p[5], addr6p[6], addr6p[7],
|
|
&if_idx, &plen, &scope, &dad_status, devname) != EOF) {
|
|
if (!strcmp(devname, if_conf->ifname)) {
|
|
sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
|
|
addr6p[0], addr6p[1], addr6p[2], addr6p[3],
|
|
addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
|
|
inet6_aftype.input(1, addr6, (struct sockaddr *) &sap);
|
|
printf(_(" inet6 addr: %s/%d"),
|
|
inet6_aftype.sprint((struct sockaddr *) &sap, 1), plen);
|
|
printf(_(" Scope:"));
|
|
switch (scope) {
|
|
case 0:
|
|
printf(_("Global"));
|
|
break;
|
|
case IPV6_ADDR_LINKLOCAL:
|
|
printf(_("Link"));
|
|
break;
|
|
case IPV6_ADDR_SITELOCAL:
|
|
printf(_("Site"));
|
|
break;
|
|
case IPV6_ADDR_COMPATv4:
|
|
printf(_("Compat"));
|
|
break;
|
|
case IPV6_ADDR_LOOPBACK:
|
|
printf(_("Host"));
|
|
break;
|
|
default:
|
|
printf(_("Unknown"));
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
fclose(f);
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
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) != 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) != 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) != 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;
|
|
}
|
|
|