diff --git a/libnozzle/libnozzle.c b/libnozzle/libnozzle.c index 0ea6e0c6..6cd5c634 100644 --- a/libnozzle/libnozzle.c +++ b/libnozzle/libnozzle.c @@ -1,1142 +1,1134 @@ /* * Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. * * Author: Fabio M. Di Nitto * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef KNET_LINUX #include #include #endif #ifdef KNET_BSD #include #endif #include "libnozzle.h" #include "internals.h" /* * internal functions are all _unlocked_ * locking should be handled at external API functions */ static int lib_init = 0; static struct nozzle_lib_config lib_cfg; static pthread_mutex_t config_mutex = PTHREAD_MUTEX_INITIALIZER; /* * internal helpers */ -static void _close(nozzle_t nozzle) -{ -#ifdef KNET_BSD - struct ifreq ifr; -#endif - - if (!nozzle) - return; - - if (nozzle->fd) - close(nozzle->fd); - -#ifdef KNET_BSD - memset(&ifr, 0, sizeof(struct ifreq)); - strncpy(ifname, nozzle->name, IFNAMSIZ); - - ioctl(lib_cfg.ioctlfd, SIOCIFDESTROY, &ifr); -#endif - - free(nozzle); - - return; -} - -static void _close_cfg(void) -{ - if (lib_cfg.head == NULL) { - close(lib_cfg.ioctlfd); - lib_init = 0; - } -} - static int _set_ip(nozzle_t nozzle, const char *command, const char *ipaddr, const char *prefix, char **error_string, int secondary) { char *broadcast = NULL; char cmdline[4096]; #ifdef KNET_BSD char proto[6]; int v4 = 1; snprintf(proto, sizeof(proto), "inet"); #endif if (!strchr(ipaddr, ':')) { broadcast = generate_v4_broadcast(ipaddr, prefix); if (!broadcast) { errno = EINVAL; return -1; } } #ifdef KNET_BSD else { v4 = 0; snprintf(proto, sizeof(proto), "inet6"); } #endif memset(cmdline, 0, sizeof(cmdline)); #ifdef KNET_LINUX if (broadcast) { snprintf(cmdline, sizeof(cmdline)-1, "ip addr %s %s/%s dev %s broadcast %s", command, ipaddr, prefix, nozzle->name, broadcast); } else { snprintf(cmdline, sizeof(cmdline)-1, "ip addr %s %s/%s dev %s", command, ipaddr, prefix, nozzle->name); } #endif #ifdef KNET_BSD if (!strcmp(command, "add")) { snprintf(cmdline, sizeof(cmdline)-1, "ifconfig %s %s %s/%s", nozzle->name, proto, ipaddr, prefix); if (broadcast) { snprintf(cmdline + strlen(cmdline), sizeof(cmdline) - strlen(cmdline) -1, " broadcast %s", broadcast); } if ((secondary) && (v4)) { snprintf(cmdline + strlen(cmdline), sizeof(cmdline) - strlen(cmdline) -1, " alias"); } } else { snprintf(cmdline, sizeof(cmdline)-1, "ifconfig %s %s %s/%s delete", nozzle->name, proto, ipaddr, prefix); } #endif if (broadcast) { free(broadcast); } return execute_bin_sh_command(cmdline, error_string); } /* * internal helpers below should be completed * * keep all ioctl work within this file */ +static void lib_fini(void) +{ + if (lib_cfg.head == NULL) { + close(lib_cfg.ioctlfd); + lib_init = 0; + } +} + +static void destroy_iface(nozzle_t nozzle) +{ +#ifdef KNET_BSD + struct ifreq ifr; +#endif + + if (!nozzle) + return; + + if (nozzle->fd) + close(nozzle->fd); + +#ifdef KNET_BSD + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifname, nozzle->name, IFNAMSIZ); + + ioctl(lib_cfg.ioctlfd, SIOCIFDESTROY, &ifr); +#endif + + free(nozzle); + + lib_fini(); + + return; +} + static int is_valid_nozzle(const nozzle_t nozzle) { nozzle_t temp; if (!nozzle) { return 0; } if (!lib_init) { return 0; } temp = lib_cfg.head; while (temp != NULL) { if (nozzle == temp) return 1; temp = temp->next; } return 0; } static int get_iface_mtu(const nozzle_t nozzle) { int err = 0, savederrno = 0; struct ifreq ifr; memset(&ifr, 0, sizeof(struct ifreq)); strncpy(ifname, nozzle->name, IFNAMSIZ); err = ioctl(lib_cfg.ioctlfd, SIOCGIFMTU, &ifr); if (err) { savederrno = errno; goto out_clean; } err = ifr.ifr_mtu; out_clean: errno = savederrno; return err; } static int get_iface_mac(const nozzle_t nozzle, char **ether_addr) { int err = 0, savederrno = 0; struct ifreq ifr; char mac[MACADDR_CHAR_MAX]; #ifdef KNET_BSD struct ifaddrs *ifap = NULL; struct ifaddrs *ifa; int found = 0; #endif memset(&mac, 0, MACADDR_CHAR_MAX); memset(&ifr, 0, sizeof(struct ifreq)); strncpy(ifname, nozzle->name, IFNAMSIZ); #ifdef KNET_LINUX err = ioctl(lib_cfg.ioctlfd, SIOCGIFHWADDR, &ifr); if (err) { savederrno = errno; goto out_clean; } ether_ntoa_r((struct ether_addr *)ifr.ifr_hwaddr.sa_data, mac); #endif #ifdef KNET_BSD /* * there is no ioctl to get the ether address of an interface on FreeBSD * (not to be confused with hwaddr). Use workaround described here: * https://lists.freebsd.org/pipermail/freebsd-hackers/2004-June/007394.html */ err = getifaddrs(&ifap); if (err < 0) { savederrno = errno; goto out_clean; } ifa = ifap; while (ifa) { if (!strncmp(nozzle->name, ifa->ifa_name, IFNAMSIZ)) { found = 1; break; } ifa=ifa->ifa_next; } if (found) { ether_ntoa_r((struct ether_addr *)LLADDR((struct sockaddr_dl *)ifa->ifa_addr), mac); } else { errno = EINVAL; err = -1; } freeifaddrs(ifap); if (err) { goto out_clean; } #endif *ether_addr = strdup(mac); if (!*ether_addr) { savederrno = errno; err = -1; } out_clean: errno = savederrno; return err; } static int set_iface_down(nozzle_t nozzle) { int err = 0, savederrno = 0; struct ifreq ifr; if (!nozzle->up) { goto out_clean; } memset(&ifr, 0, sizeof(struct ifreq)); strncpy(ifname, nozzle->name, IFNAMSIZ); err = ioctl(lib_cfg.ioctlfd, SIOCGIFFLAGS, &ifr); if (err) { savederrno = errno; goto out_clean; } ifr.ifr_flags &= ~IFF_UP; err = ioctl(lib_cfg.ioctlfd, SIOCSIFFLAGS, &ifr); if (err) { savederrno = errno; goto out_clean; } nozzle->up = 0; out_clean: errno = savederrno; return err; } /* * public API */ -nozzle_t nozzle_open(char *devname, size_t devname_size, const char *updownpath) -{ - int savederrno = 0; - nozzle_t nozzle = NULL; - char *temp_mac = NULL; -#ifdef KNET_LINUX - struct ifreq ifr; -#endif -#ifdef KNET_BSD - uint16_t i; - long int nozzlenum = 0; - char curnozzle[IFNAMSIZ]; -#endif - - if (devname == NULL) { - errno = EINVAL; - return NULL; - } - - if (devname_size < IFNAMSIZ) { - errno = EINVAL; - return NULL; - } - - if (strlen(devname) > IFNAMSIZ) { - errno = E2BIG; - return NULL; - } - -#ifdef KNET_BSD - /* - * BSD does not support named devices like Linux - * but it is possible to force a nozzleX device number - * where X is 0 to 255. - */ - if (strlen(devname)) { - if (strncmp(devname, "tap", 3)) { - errno = EINVAL; - return NULL; - } - errno = 0; - nozzlenum = strtol(devname+3, NULL, 10); - if (errno) { - errno = EINVAL; - return NULL; - } - if ((nozzlenum < 0) || (nozzlenum > 255)) { - errno = EINVAL; - return NULL; - } - } -#endif - - if (updownpath) { - /* only absolute paths */ - if (updownpath[0] != '/') { - errno = EINVAL; - return NULL; - } - if (strlen(updownpath) >= UPDOWN_PATH_MAX) { - errno = E2BIG; - return NULL; - } - } - - savederrno = pthread_mutex_lock(&config_mutex); - if (savederrno) { - errno = savederrno; - return NULL; - } - - if (!lib_init) { - lib_cfg.head = NULL; -#ifdef KNET_LINUX - lib_cfg.ioctlfd = socket(AF_INET, SOCK_STREAM, 0); -#endif -#ifdef KNET_BSD - lib_cfg.ioctlfd = socket(AF_LOCAL, SOCK_DGRAM, 0); -#endif - if (lib_cfg.ioctlfd < 0) { - savederrno = errno; - goto out_error; - } - lib_init = 1; - } - - nozzle = malloc(sizeof(struct nozzle_iface)); - if (!nozzle) { - savederrno = ENOMEM; - goto out_error; - } - - memset(nozzle, 0, sizeof(struct nozzle_iface)); - -#ifdef KNET_BSD - if (!strlen(devname)) { - for (i = 0; i < 256; i++) { - snprintf(curnozzle, sizeof(curnozzle) - 1, "/dev/tap%u", i); - nozzle->fd = open(curnozzle, O_RDWR); - savederrno = errno; - if (nozzle->fd > 0) { - break; - } - } - snprintf(curnozzle, sizeof(curnozzle) -1 , "tap%u", i); - } else { - snprintf(curnozzle, sizeof(curnozzle) - 1, "/dev/%s", devname); - nozzle->fd = open(curnozzle, O_RDWR); - savederrno = errno; - snprintf(curnozzle, sizeof(curnozzle) - 1, "%s", devname); - } - if (nozzle->fd < 0) { - errno = EBUSY; - goto out_error; - } - strncpy(devname, curnozzle, IFNAMSIZ); - strncpy(nozzle->name, curnozzle, IFNAMSIZ); -#endif - -#ifdef KNET_LINUX - if ((nozzle->fd = open("/dev/net/tun", O_RDWR)) < 0) { - savederrno = errno; - goto out_error; - } - - memset(&ifr, 0, sizeof(struct ifreq)); - strncpy(ifname, devname, IFNAMSIZ); - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - - if (ioctl(nozzle->fd, TUNSETIFF, &ifr) < 0) { - savederrno = errno; - goto out_error; - } - - if ((strlen(devname) > 0) && (strcmp(devname, ifname) != 0)) { - errno = EBUSY; - goto out_error; - } - - strncpy(devname, ifname, IFNAMSIZ); - strncpy(nozzle->name, ifname, IFNAMSIZ); -#endif - - nozzle->default_mtu = get_iface_mtu(nozzle); - if (nozzle->default_mtu < 0) { - savederrno = errno; - goto out_error; - } - - if (get_iface_mac(nozzle, &temp_mac) < 0) { - savederrno = errno; - goto out_error; - } - - strncpy(nozzle->default_mac, temp_mac, 18); - free(temp_mac); - - if (updownpath) { - int len = strlen(updownpath); - - strcpy(nozzle->updownpath, updownpath); - if (nozzle->updownpath[len-1] != '/') { - nozzle->updownpath[len] = '/'; - } - nozzle->hasupdown = 1; - } - - nozzle->next = lib_cfg.head; - lib_cfg.head = nozzle; - - pthread_mutex_unlock(&config_mutex); - errno = savederrno; - return nozzle; - -out_error: - _close(nozzle); - _close_cfg(); - pthread_mutex_unlock(&config_mutex); - errno = savederrno; - return NULL; -} - -int nozzle_close(nozzle_t nozzle) -{ - int err = 0, savederrno = 0; - nozzle_t temp = lib_cfg.head; - nozzle_t prev = lib_cfg.head; - struct nozzle_ip *ip, *ip_next; - char *error_string = NULL; - - savederrno = pthread_mutex_lock(&config_mutex); - if (savederrno) { - errno = savederrno; - return -1; - } - - if (!is_valid_nozzle(nozzle)) { - savederrno = EINVAL; - err = -1; - goto out_clean; - } - - while ((temp) && (temp != nozzle)) { - prev = temp; - temp = temp->next; - } - - if (nozzle == prev) { - lib_cfg.head = nozzle->next; - } else { - prev->next = nozzle->next; - } - - set_iface_down(nozzle); - - ip = nozzle->ip; - while (ip) { - ip_next = ip->next; - _set_ip(nozzle, "del", ip->ipaddr, ip->prefix, &error_string, 0); - if (error_string) { - free(error_string); - error_string = NULL; - } - free(ip); - ip = ip_next; - } - - _close(nozzle); - _close_cfg(); - -out_clean: - pthread_mutex_unlock(&config_mutex); - errno = savederrno; - return err; -} - int nozzle_set_mtu(nozzle_t nozzle, const int mtu, char **error_string) { int err = 0, savederrno = 0; struct nozzle_ip *tmp_ip; struct ifreq ifr; if ((!mtu) || (!error_string)) { errno = EINVAL; return -1; } savederrno = pthread_mutex_lock(&config_mutex); if (savederrno) { errno = savederrno; return -1; } if (!is_valid_nozzle(nozzle)) { savederrno = EINVAL; err = -1; goto out_clean; } err = nozzle->current_mtu = get_iface_mtu(nozzle); if (err < 0) { savederrno = errno; goto out_clean; } memset(&ifr, 0, sizeof(struct ifreq)); strncpy(ifname, nozzle->name, IFNAMSIZ); ifr.ifr_mtu = mtu; err = ioctl(lib_cfg.ioctlfd, SIOCSIFMTU, &ifr); if (err) { savederrno = errno; goto out_clean; } if ((nozzle->current_mtu < 1280) && (mtu >= 1280)) { tmp_ip = nozzle->ip; while(tmp_ip) { if (tmp_ip->domain == AF_INET6) { err = _set_ip(nozzle, "add", tmp_ip->ipaddr, tmp_ip->prefix, error_string, 0); if (err) { savederrno = errno; err = -1; goto out_clean; } } tmp_ip = tmp_ip->next; } } out_clean: pthread_mutex_unlock(&config_mutex); errno = savederrno; return err; } int nozzle_reset_mtu(nozzle_t nozzle, char **error_string) { return nozzle_set_mtu(nozzle, nozzle->default_mtu, error_string); } int nozzle_add_ip(nozzle_t nozzle, const char *ipaddr, const char *prefix, char **error_string) { int err = 0, savederrno = 0; int found = 0; struct nozzle_ip *ip = NULL, *ip_prev = NULL, *ip_last = NULL; int secondary = 0; if ((!ipaddr) || (!prefix) || (!error_string)) { errno = EINVAL; return -1; } savederrno = pthread_mutex_lock(&config_mutex); if (savederrno) { errno = savederrno; return -1; } if (!is_valid_nozzle(nozzle)) { savederrno = EINVAL; err = -1; goto out_clean; } found = find_ip(nozzle, ipaddr, prefix, &ip, &ip_prev); if (found) { goto out_clean; } ip = malloc(sizeof(struct nozzle_ip)); if (!ip) { savederrno = errno; err = -1 ; goto out_clean; } memset(ip, 0, sizeof(struct nozzle_ip)); strncpy(ip->ipaddr, ipaddr, IPADDR_CHAR_MAX); strncpy(ip->prefix, prefix, PREFIX_CHAR_MAX); if (!strchr(ip->ipaddr, ':')) { ip->domain = AF_INET; } else { ip->domain = AF_INET6; } /* * if user asks for an IPv6 address, but MTU < 1280 * store the IP and bring it up later if and when MTU > 1280 */ if ((ip->domain == AF_INET6) && (get_iface_mtu(nozzle) < 1280)) { err = 0; } else { if (nozzle->ip) { secondary = 1; } err = _set_ip(nozzle, "add", ipaddr, prefix, error_string, secondary); savederrno = errno; } if (err) { free(ip); goto out_clean; } if (nozzle->ip) { ip_last = nozzle->ip; while (ip_last->next != NULL) { ip_last = ip_last->next; } ip_last->next = ip; } else { nozzle->ip = ip; } out_clean: pthread_mutex_unlock(&config_mutex); errno = savederrno; return err; } int nozzle_del_ip(nozzle_t nozzle, const char *ipaddr, const char *prefix, char **error_string) { int err = 0, savederrno = 0; int found = 0; struct nozzle_ip *ip = NULL, *ip_prev = NULL; if ((!ipaddr) || (!prefix) || (!error_string)) { errno = EINVAL; return -1; } savederrno = pthread_mutex_lock(&config_mutex); if (savederrno) { errno = savederrno; return -1; } if (!is_valid_nozzle(nozzle)) { savederrno = EINVAL; err = -1; goto out_clean; } found = find_ip(nozzle, ipaddr, prefix, &ip, &ip_prev); if (!found) { goto out_clean; } err = _set_ip(nozzle, "del", ipaddr, prefix, error_string, 0); savederrno = errno; if (!err) { if (ip == ip_prev) { nozzle->ip = ip->next; } else { ip_prev->next = ip->next; } free(ip); } out_clean: pthread_mutex_unlock(&config_mutex); errno = savederrno; return err; } int nozzle_get_ips(const nozzle_t nozzle, char **ipaddr_list, int *entries) { int err = 0, savederrno = 0; int found = 0; char *ip_list = NULL; int size = 0, offset = 0, len; struct nozzle_ip *ip = NULL; if ((!ipaddr_list) || (!entries)) { errno = EINVAL; return -1; } savederrno = pthread_mutex_lock(&config_mutex); if (savederrno) { errno = savederrno; return -1; } if (!is_valid_nozzle(nozzle)) { savederrno = EINVAL; goto out_clean; } ip = nozzle->ip; while (ip) { found++; ip = ip->next; } if (!found) { *ipaddr_list = NULL; *entries = 0; goto out_clean; } size = found * (IPADDR_CHAR_MAX + PREFIX_CHAR_MAX + 2); ip_list = malloc(size); if (!ip_list) { savederrno = errno; err = -1; goto out_clean; } memset(ip_list, 0, size); ip = nozzle->ip; while (ip) { len = strlen(ip->ipaddr); memmove(ip_list + offset, ip->ipaddr, len); offset = offset + len + 1; len = strlen(ip->prefix); memmove(ip_list + offset, ip->prefix, len); offset = offset + len + 1; ip = ip->next; } *ipaddr_list = ip_list; *entries = found; out_clean: pthread_mutex_unlock(&config_mutex); errno = savederrno; return err; } int nozzle_run_updown(const nozzle_t nozzle, uint8_t action, char **exec_string) { int err = 0, savederrno = 0; char command[PATH_MAX]; const char *action_str = NULL; struct stat sb; if (action > NOZZLE_POSTDOWN) { errno = EINVAL; return -1; } if (!exec_string) { errno = EINVAL; return -1; } savederrno = pthread_mutex_lock(&config_mutex); if (savederrno) { errno = savederrno; return -1; } if (!is_valid_nozzle(nozzle)) { savederrno = EINVAL; err = -1; goto out_clean; } if (!nozzle->hasupdown) { savederrno = EINVAL; err = -1; goto out_clean; } switch(action) { case NOZZLE_PREUP: action_str = "pre-up.d"; break; case NOZZLE_UP: action_str = "up.d"; break; case NOZZLE_DOWN: action_str = "down.d"; break; case NOZZLE_POSTDOWN: action_str = "post-down.d"; break; } memset(command, 0, PATH_MAX); snprintf(command, PATH_MAX, "%s%s/%s", nozzle->updownpath, action_str, nozzle->name); err = stat(command, &sb); if (err) { savederrno = errno; goto out_clean; } err = execute_bin_sh_command(command, exec_string); savederrno = errno; out_clean: pthread_mutex_unlock(&config_mutex); errno = savederrno; return err; } /* * functions below should be completed */ +nozzle_t nozzle_open(char *devname, size_t devname_size, const char *updownpath) +{ + int savederrno = 0; + nozzle_t nozzle = NULL; + char *temp_mac = NULL; +#ifdef KNET_LINUX + struct ifreq ifr; +#endif +#ifdef KNET_BSD + uint16_t i; + long int nozzlenum = 0; + char curnozzle[IFNAMSIZ]; +#endif + + if (devname == NULL) { + errno = EINVAL; + return NULL; + } + + if (devname_size < IFNAMSIZ) { + errno = EINVAL; + return NULL; + } + + if (strlen(devname) > IFNAMSIZ) { + errno = E2BIG; + return NULL; + } + +#ifdef KNET_BSD + /* + * BSD does not support named devices like Linux + * but it is possible to force a nozzleX device number + * where X is 0 to 255. + */ + if (strlen(devname)) { + if (strncmp(devname, "tap", 3)) { + errno = EINVAL; + return NULL; + } + errno = 0; + nozzlenum = strtol(devname+3, NULL, 10); + if (errno) { + errno = EINVAL; + return NULL; + } + if ((nozzlenum < 0) || (nozzlenum > 255)) { + errno = EINVAL; + return NULL; + } + } +#endif + + if (updownpath) { + /* only absolute paths */ + if (updownpath[0] != '/') { + errno = EINVAL; + return NULL; + } + if (strlen(updownpath) >= UPDOWN_PATH_MAX) { + errno = E2BIG; + return NULL; + } + } + + savederrno = pthread_mutex_lock(&config_mutex); + if (savederrno) { + errno = savederrno; + return NULL; + } + + if (!lib_init) { + lib_cfg.head = NULL; +#ifdef KNET_LINUX + lib_cfg.ioctlfd = socket(AF_INET, SOCK_STREAM, 0); +#endif +#ifdef KNET_BSD + lib_cfg.ioctlfd = socket(AF_LOCAL, SOCK_DGRAM, 0); +#endif + if (lib_cfg.ioctlfd < 0) { + savederrno = errno; + goto out_error; + } + lib_init = 1; + } + + nozzle = malloc(sizeof(struct nozzle_iface)); + if (!nozzle) { + savederrno = ENOMEM; + goto out_error; + } + + memset(nozzle, 0, sizeof(struct nozzle_iface)); + +#ifdef KNET_BSD + if (!strlen(devname)) { + for (i = 0; i < 256; i++) { + snprintf(curnozzle, sizeof(curnozzle) - 1, "/dev/tap%u", i); + nozzle->fd = open(curnozzle, O_RDWR); + savederrno = errno; + if (nozzle->fd > 0) { + break; + } + } + snprintf(curnozzle, sizeof(curnozzle) -1 , "tap%u", i); + } else { + snprintf(curnozzle, sizeof(curnozzle) - 1, "/dev/%s", devname); + nozzle->fd = open(curnozzle, O_RDWR); + savederrno = errno; + snprintf(curnozzle, sizeof(curnozzle) - 1, "%s", devname); + } + if (nozzle->fd < 0) { + errno = EBUSY; + goto out_error; + } + strncpy(devname, curnozzle, IFNAMSIZ); + strncpy(nozzle->name, curnozzle, IFNAMSIZ); +#endif + +#ifdef KNET_LINUX + if ((nozzle->fd = open("/dev/net/tun", O_RDWR)) < 0) { + savederrno = errno; + goto out_error; + } + + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifname, devname, IFNAMSIZ); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + + if (ioctl(nozzle->fd, TUNSETIFF, &ifr) < 0) { + savederrno = errno; + goto out_error; + } + + if ((strlen(devname) > 0) && (strcmp(devname, ifname) != 0)) { + errno = EBUSY; + goto out_error; + } + + strncpy(devname, ifname, IFNAMSIZ); + strncpy(nozzle->name, ifname, IFNAMSIZ); +#endif + + nozzle->default_mtu = get_iface_mtu(nozzle); + if (nozzle->default_mtu < 0) { + savederrno = errno; + goto out_error; + } + + if (get_iface_mac(nozzle, &temp_mac) < 0) { + savederrno = errno; + goto out_error; + } + + strncpy(nozzle->default_mac, temp_mac, 18); + free(temp_mac); + + if (updownpath) { + int len = strlen(updownpath); + + strcpy(nozzle->updownpath, updownpath); + if (nozzle->updownpath[len-1] != '/') { + nozzle->updownpath[len] = '/'; + } + nozzle->hasupdown = 1; + } + + nozzle->next = lib_cfg.head; + lib_cfg.head = nozzle; + + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return nozzle; + +out_error: + destroy_iface(nozzle); + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return NULL; +} + +int nozzle_close(nozzle_t nozzle) +{ + int err = 0, savederrno = 0; + nozzle_t temp = lib_cfg.head; + nozzle_t prev = lib_cfg.head; + struct nozzle_ip *ip, *ip_next; + + savederrno = pthread_mutex_lock(&config_mutex); + if (savederrno) { + errno = savederrno; + return -1; + } + + if (!is_valid_nozzle(nozzle)) { + savederrno = EINVAL; + err = -1; + goto out_clean; + } + + while ((temp) && (temp != nozzle)) { + prev = temp; + temp = temp->next; + } + + if (nozzle == prev) { + lib_cfg.head = nozzle->next; + } else { + prev->next = nozzle->next; + } + + ip = nozzle->ip; + while (ip) { + ip_next = ip->next; + free(ip); + ip = ip_next; + } + + destroy_iface(nozzle); + +out_clean: + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return err; +} + int nozzle_set_up(nozzle_t nozzle) { int err = 0, savederrno = 0; struct ifreq ifr; savederrno = pthread_mutex_lock(&config_mutex); if (savederrno) { errno = savederrno; return -1; } if (!is_valid_nozzle(nozzle)) { savederrno = EINVAL; err = -1; goto out_clean; } if (nozzle->up) { goto out_clean; } memset(&ifr, 0, sizeof(struct ifreq)); strncpy(ifname, nozzle->name, IFNAMSIZ); err = ioctl(lib_cfg.ioctlfd, SIOCGIFFLAGS, &ifr); if (err) { savederrno = errno; goto out_clean; } ifr.ifr_flags |= IFF_UP | IFF_RUNNING; err = ioctl(lib_cfg.ioctlfd, SIOCSIFFLAGS, &ifr); if (err) { savederrno = errno; goto out_clean; } nozzle->up = 1; out_clean: pthread_mutex_unlock(&config_mutex); errno = savederrno; return err; } int nozzle_set_down(nozzle_t nozzle) { int err = 0, savederrno = 0; savederrno = pthread_mutex_lock(&config_mutex); if (savederrno) { errno = savederrno; return -1; } if (!is_valid_nozzle(nozzle)) { savederrno = EINVAL; err = -1; goto out_clean; } err = set_iface_down(nozzle); savederrno = errno; out_clean: pthread_mutex_unlock(&config_mutex); errno = savederrno; return err; } int nozzle_get_mtu(const nozzle_t nozzle) { int err = 0, savederrno = 0; savederrno = pthread_mutex_lock(&config_mutex); if (savederrno) { errno = savederrno; return -1; } if (!is_valid_nozzle(nozzle)) { savederrno = EINVAL; err = -1; goto out_clean; } err = get_iface_mtu(nozzle); savederrno = errno; out_clean: pthread_mutex_unlock(&config_mutex); savederrno = errno; return err; } int nozzle_get_mac(const nozzle_t nozzle, char **ether_addr) { int err = 0, savederrno = 0; if (!ether_addr) { errno = EINVAL; return -1; } savederrno = pthread_mutex_lock(&config_mutex); if (savederrno) { errno = savederrno; return -1; } if (!is_valid_nozzle(nozzle)) { savederrno = EINVAL; err = -1; goto out_clean; } err = get_iface_mac(nozzle, ether_addr); out_clean: pthread_mutex_unlock(&config_mutex); errno = savederrno; return err; } int nozzle_set_mac(nozzle_t nozzle, const char *ether_addr) { int err = 0, savederrno = 0; struct ifreq ifr; if (!ether_addr) { errno = EINVAL; return -1; } savederrno = pthread_mutex_lock(&config_mutex); if (savederrno) { errno = savederrno; return -1; } if (!is_valid_nozzle(nozzle)) { savederrno = EINVAL; err = -1; goto out_clean; } memset(&ifr, 0, sizeof(struct ifreq)); strncpy(ifname, nozzle->name, IFNAMSIZ); #ifdef KNET_LINUX err = ioctl(lib_cfg.ioctlfd, SIOCGIFHWADDR, &ifr); if (err) { savederrno = errno; goto out_clean; } memmove(ifr.ifr_hwaddr.sa_data, ether_aton(ether_addr), ETH_ALEN); err = ioctl(lib_cfg.ioctlfd, SIOCSIFHWADDR, &ifr); savederrno = errno; #endif #ifdef KNET_BSD err = ioctl(lib_cfg.ioctlfd, SIOCGIFADDR, &ifr); if (err) { savederrno = errno; goto out_clean; } memmove(ifr.ifr_addr.sa_data, ether_aton(ether_addr), ETHER_ADDR_LEN); ifr.ifr_addr.sa_len = ETHER_ADDR_LEN; err = ioctl(lib_cfg.ioctlfd, SIOCSIFLLADDR, &ifr); savederrno = errno; #endif out_clean: pthread_mutex_unlock(&config_mutex); errno = savederrno; return err; } int nozzle_reset_mac(nozzle_t nozzle) { return nozzle_set_mac(nozzle, nozzle->default_mac); } nozzle_t nozzle_get_handle_by_name(const char *devname) { int savederrno = 0; nozzle_t nozzle; if ((devname == NULL) || (strlen(devname) > IFNAMSIZ)) { errno = EINVAL; return NULL; } savederrno = pthread_mutex_lock(&config_mutex); if (savederrno) { errno = savederrno; return NULL; } nozzle = lib_cfg.head; while (nozzle != NULL) { if (!strcmp(devname, nozzle->name)) break; nozzle = nozzle->next; } if (!nozzle) { savederrno = ENOENT; } pthread_mutex_unlock(&config_mutex); errno = savederrno; return nozzle; } const char *nozzle_get_name_by_handle(const nozzle_t nozzle) { int savederrno = 0; char *name = NULL; savederrno = pthread_mutex_lock(&config_mutex); if (savederrno) { errno = savederrno; return NULL; } if (!is_valid_nozzle(nozzle)) { savederrno = ENOENT; goto out_clean; } name = nozzle->name; out_clean: pthread_mutex_unlock(&config_mutex); errno = savederrno; return name; } int nozzle_get_fd(const nozzle_t nozzle) { int fd = -1, savederrno = 0; savederrno = pthread_mutex_lock(&config_mutex); if (savederrno) { errno = savederrno; return -1; } if (!is_valid_nozzle(nozzle)) { savederrno = ENOENT; fd = -1; goto out_clean; } fd = nozzle->fd; out_clean: pthread_mutex_unlock(&config_mutex); errno = savederrno; return fd; }