#include "configm.h" #include "ipconfig.h" #include "rpc.h" #include "parsefile.h" uchar ip_masklen(struct in_addr netmask) { uint tmp = ~ntohl(netmask.s_addr); if (tmp) /* clz: count leading zeroes. sadly, the behaviour of this * builtin * is undefined for a 0 argument, even though most CPUs give 32 */ return __builtin_clz(tmp); else return 32; } /* Convert masklen into IP address's netmask (network byte order). */ void masklen2ip(const int masklen, struct in_addr *netmask) { if(masklen < 0 || masklen > IPV4_MAX_BITLEN) { return; } /* left shift is only defined for less than the size of the type. * we unconditionally use long long in case the target platform * has defined behaviour for << 32 (or has a 64-bit left shift) */ if (sizeof(unsigned long long) > 4) netmask->s_addr = htonl(0xffffffffULL << (32 - masklen)); else netmask->s_addr = htonl(masklen ? 0xffffffffU << (32 - masklen) : 0); } void ip_save_file(ip_config_t *ip_conf, uint config_type) { char *addr_name = "address"; char *mask_name = "netmask"; struct in_addr netmask; char addr_buff[IF_BUFF_LEN] = {0}; char mask_buff[IF_BUFF_LEN] = {0}; if(config_type == CM_CONFIG_SET) { sprintf(addr_buff, "address %s\n", inet_ntoa(ip_conf->prefix)); masklen2ip(ip_conf->prefixlen, &netmask); sprintf(mask_buff, "netmask %s\n", inet_ntoa(netmask)); printf("%s,%s\r\n",addr_buff, mask_buff); set_if_config(ip_conf->ifname, addr_name, addr_buff); set_if_config(ip_conf->ifname, mask_name, mask_buff); } else if(config_type == CM_CONFIG_DEL) { del_if_config(ip_conf->ifname, addr_name); del_if_config(ip_conf->ifname, mask_name); } } /* call ioctl system call */ ret_code if_ioctl(unsigned long request, caddr_t ifreq, int *ret) { int sock; int err = 0; *ret = 0; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { rpc_log_error("Cannot create UDP socket"); return RET_SOCKERR; } if ((*ret = ioctl(sock, request, ifreq)) < 0) { err = errno; rpc_log_error("Ioctl error: %s\n", strerror(errno)); } close(sock); if (*ret < 0) { errno = err; *ret = err; return RET_SYSERR; } return RET_OK; } ret_code if_set_prefix(ip_config_t *ip_conf, int *code) { ret_code ret; struct ifreq ifreq; struct sockaddr_in addr; struct sockaddr_in mask; strncpy(ifreq.ifr_name, ip_conf->ifname, sizeof(ifreq.ifr_name)); addr.sin_addr = ip_conf->prefix; addr.sin_family = ip_conf->family; memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in)); ret = if_ioctl(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(SIOCSIFNETMASK, (caddr_t)&ifreq, code); ASSERT_RET(ret); } return 0; } ret_code if_get_prefix_all(ip_config_t *ip_conf, short *single_len, int *cnt, int *code) { struct ifreq ifreq[MAX_IF_NUM]; struct sockaddr_in *addr; struct ifreq netmask; struct ifconf ifc; int if_count = 0; ret_code ret; int mask_ret; int i; memset(&ifc, 0, sizeof(struct ifconf)); memset(&ifreq, 0, MAX_IF_NUM * sizeof(struct ifreq)); ifc.ifc_len = MAX_IF_NUM * sizeof(struct ifreq); ifc.ifc_buf = (char *)ifreq; ret = if_ioctl(SIOCGIFCONF, (caddr_t)&ifc, code); ASSERT_RET(ret); if_count = ifc.ifc_len / (sizeof(struct ifreq)); rpc_log_info("if num is %d\n", if_count); if(if_count * sizeof(ip_config_t) > CM_BUFF_SIZE) { ret = RET_NOMEM; ASSERT_RET(ret); } *cnt = 0; for(i = 0; i < if_count; i++) { rpc_log_info("get interface %s info\n", ifreq[i].ifr_name); strncpy(ip_conf[i].ifname, ifreq[i].ifr_name, INTERFACE_NAMSIZ); ip_conf[i].family = AF_INET; ip_conf[i].prefix = ((struct sockaddr_in *)&(ifreq[i].ifr_addr))->sin_addr; memset(&netmask, 0, sizeof(netmask)); strncpy(netmask.ifr_name, ifreq[i].ifr_name, sizeof(netmask.ifr_name)); ret = if_ioctl(SIOCGIFNETMASK, (caddr_t)&netmask, &mask_ret); ASSERT_RET_NO(ret); addr = ( struct sockaddr_in * )&(netmask.ifr_netmask ); ip_conf[i].prefixlen = ip_masklen(addr->sin_addr); single_len[i] = sizeof(ip_config_t); (*cnt)++; } return RET_OK; } ret_code if_get_prefix(ip_config_t *ip_conf, int *code) { struct sockaddr_in *addr; struct ifreq netmask; struct ifreq ifreq; ret_code ret = RET_OK; int mask_ret; int i; if(ip_conf->family != AF_INET) { ret = RET_INPUTERR; } ASSERT_RET(ret); memset(&ifreq, 0, sizeof(struct ifreq)); rpc_log_info("get interface %s info\n", ip_conf->ifname); strncpy(ifreq.ifr_name, ip_conf->ifname, sizeof(ifreq.ifr_name)); ret = if_ioctl(SIOCGIFADDR, (caddr_t)&ifreq, code); ASSERT_RET(ret); ip_conf->prefix = ((struct sockaddr_in *)&(ifreq.ifr_addr))->sin_addr; memset(&ifreq, 0, sizeof(ifreq)); strncpy(ifreq.ifr_name, ip_conf->ifname, sizeof(ifreq.ifr_name)); ret = if_ioctl(SIOCGIFNETMASK, (caddr_t)&ifreq, &mask_ret); ASSERT_RET_NO(ret); addr = ( struct sockaddr_in * )&(ifreq.ifr_netmask); ip_conf->prefixlen = ip_masklen(addr->sin_addr); return ret; } ret_code ip_config_set_chk(uint source,uint config_type, pointer input, int input_len, pointer output, int *output_len) { ret_code ret = RET_OK; ip_config_t *ip_conf; ip_conf = (ip_config_t *)input; if(input_len < sizeof(ip_config_t) || strlen(ip_conf->ifname) == 0) { ret = RET_INPUTERR; } if (ipv4_martian(&ip_conf->prefix)) { ret = RET_IPINVALID; } ASSERT_RET(ret); if(ip_conf->prefixlen == 0 || ip_conf->prefixlen > IPV4_MAX_PREFIXLEN) { ip_conf->prefixlen = IPV4_DEFAULT_PREFIXLEN; } return RET_OK; } ret_code ip_config_get_chk(uint source,uint config_type, pointer input, int input_len, pointer output, int *output_len) { ret_code ret = RET_OK; ip_config_t *ip_conf; ip_conf = (ip_config_t *)input; if(input_len < sizeof(ip_config_t) || strlen(ip_conf->ifname) == 0 ) { ret = RET_INPUTERR; } return ret; } ret_code ip_config_getall_chk(uint source,uint config_type, pointer input, int input_len, pointer output, int *output_len) { ret_code ret = RET_OK; if(*output_len < MAX_IF_NUM * sizeof(ip_config_t)) { ret = RET_INPUTERR; } return ret; } ret_code ip_config_chk(uint source,uint config_type, pointer input, int input_len, pointer output, int *output_len) { ret_code ret = RET_OK; int code = 0; switch (config_type) { case CM_CONFIG_SET: case CM_CONFIG_DEL: ret = ip_config_set_chk(source, config_type, input, input_len, output, output_len); break; case CM_CONFIG_GET: ret = ip_config_get_chk(source, config_type, input, input_len, output, output_len); break; case CM_CONFIG_GET_ALL: ret = ip_config_getall_chk(source, config_type, input, input_len, output, output_len); break; default: ret = RET_NOTSUPPORT; } RET_ERR_FORMART(ret, code, output, *output_len); return ret; } ret_code ip_config_proc(uint source, uint config_type, pointer input, int input_len, pointer output, int *output_len) { ip_config_t *ip_conf; ret_code ret = RET_OK; int code; ip_conf = (ip_config_t *)input; if(config_type == CM_CONFIG_DEL) { ip_conf->prefix.s_addr = 0; ip_conf->prefixlen = IPV4_DEFAULT_PREFIXLEN; } rpc_log_info("config type is %d, if %s ip %s prefixlen %d\n", config_type, ip_conf->ifname, inet_ntoa(ip_conf->prefix), ip_conf->prefixlen); ret = if_set_prefix(ip_conf, &code); RET_ERR_FORMART(ret, code, output, *output_len); ASSERT_RET(ret); ip_save_file(ip_conf, config_type); return RET_OK; } ret_code ip_config_get(uint source, pointer input, int input_len, pointer output, int *output_len) { ip_config_t *ip_conf; ret_code ret = RET_OK; int code; ip_conf = (ip_config_t *)input; ret = if_get_prefix(ip_conf, &code); RET_ERR_FORMART(ret, code, output, *output_len); ASSERT_RET(ret); memcpy(output, ip_conf, sizeof(ip_config_t)); *output_len = sizeof(ip_config_t); return ret; } ret_code ip_config_get_all(uint source, uint64 config_id, pointer output, short *single_len, int *count) { int output_len = 0; ret_code ret = RET_OK; int code = 0; rpc_log_info("ip_config_get_all\r\n"); ret = if_get_prefix_all((ip_config_t *)output, single_len, count, &code); RET_ERR_FORMART(ret, code, output, output_len); ASSERT_RET(ret); return RET_OK; }