#include #include #include #include #include #include #include #include #include #include #include #include #include #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, "static")) { strcpy(if_info->v4protocol, "static"); } else { strcpy(if_info->v4protocol, "dhcp"); } 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, "static")) { strcpy(if_info->v6protocol, "static"); } else { strcpy(if_info->v6protocol, "dhcp"); } 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) { 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[addr_cnt].addr, DOT_IPV6_STR); if_conf->ipv6[addr_cnt].prefixlen = ipv6_arr[i].prefixlen; } return addr_cnt; } 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; }