tuntap.c   tuntap.c 
skipping to change at line 18 skipping to change at line 18
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <sys/types.h> #include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h> #if defined Windows
#include <arpa/inet.h> # include <winsock2.h>
#if defined Linux # include <ws2tcpip.h>
# include <netinet/ether.h>
#else #else
# include <net/if.h>
# include <netinet/in.h> # include <netinet/in.h>
# include <netinet/if_ether.h> # include <arpa/inet.h>
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <ctype.h>
#include <unistd.h>
#include "tuntap.h" #include "tuntap.h"
struct device * struct device *
tuntap_init(void) { tuntap_init(void) {
struct device *dev = NULL; struct device *dev = NULL;
if ((dev = malloc(sizeof(*dev))) == NULL) if ((dev = (struct device *)malloc(sizeof(*dev))) == NULL)
return NULL; return NULL;
(void)memset(dev->if_name, '\0', sizeof dev->if_name); (void)memset(dev->if_name, '\0', sizeof dev->if_name);
(void)memset(dev->hwaddr, '\0', sizeof dev->hwaddr); (void)memset(dev->hwaddr, '\0', sizeof dev->hwaddr);
dev->tun_fd = -1; dev->tun_fd = TUNFD_INVALID_VALUE;
dev->ctrl_sock = -1; dev->ctrl_sock = -1;
dev->flags = 0; dev->flags = 0;
tuntap_log = tuntap_log_default;
return dev; return dev;
} }
void void
tuntap_destroy(struct device *dev) { tuntap_destroy(struct device *dev) {
tuntap_sys_destroy(dev); tuntap_sys_destroy(dev);
tuntap_release(dev); tuntap_release(dev);
} }
int
tuntap_start(struct device *dev, int mode, int tun) {
int sock;
int fd;
fd = sock = -1;
/* Don't re-initialise a previously started device */
if (dev->tun_fd != -1) {
return -1;
}
/* OpenBSD needs the control socket to be ready now */
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
goto clean;
}
dev->ctrl_sock = sock;
if (mode & TUNTAP_TUNMODE_PERSIST && tun == TUNTAP_TUNID_ANY) {
goto clean; /* XXX: Explain why */
}
fd = tuntap_sys_start(dev, mode, tun);
if (fd == -1) {
goto clean;
}
dev->tun_fd = fd;
return 0;
clean:
if (fd != -1) {
(void)close(fd);
}
if (sock != -1) {
(void)close(sock);
}
return -1;
}
void
tuntap_release(struct device *dev) {
(void)close(dev->tun_fd);
(void)close(dev->ctrl_sock);
free(dev);
}
char * char *
tuntap_get_ifname(struct device *dev) { tuntap_get_ifname(struct device *dev) {
return dev->if_name; return dev->if_name;
} }
char *
tuntap_get_hwaddr(struct device *dev) {
struct ether_addr eth_attr;
(void)memcpy(&eth_attr, dev->hwaddr, sizeof dev->hwaddr);
return ether_ntoa(&eth_attr);
}
int int
tuntap_set_hwaddr(struct device *dev, const char *hwaddr) { tuntap_version(void) {
struct ether_addr *eth_addr, eth_rand; return TUNTAP_VERSION;
if (strcmp(hwaddr, "random") == 0) {
unsigned int i;
i = 0;
srandom((unsigned int)time(NULL));
for (; i < sizeof eth_rand.ether_addr_octet; ++i)
eth_rand.ether_addr_octet[i] = (unsigned char)random
();
eth_rand.ether_addr_octet[0] &= 0xfc;
eth_addr = &eth_rand;
} else {
eth_addr = ether_aton(hwaddr);
if (eth_addr == NULL) {
return -1;
}
}
(void)memcpy(dev->hwaddr, eth_addr, 6);
if (tuntap_sys_set_hwaddr(dev, eth_addr) == -1)
return -1;
return 0;
} }
int int
tuntap_up(struct device *dev) { tuntap_set_ip(struct device *dev, const char *addr, int netmask) {
struct ifreq ifr; t_tun_in_addr baddr4;
t_tun_in6_addr baddr6;
(void)memset(&ifr, '\0', sizeof ifr); uint32_t mask;
(void)memcpy(ifr.ifr_name, dev->if_name, sizeof dev->if_name); int errval;
ifr.ifr_flags = (short int)dev->flags;
ifr.ifr_flags |= IFF_UP;
if (ioctl(dev->ctrl_sock, SIOCSIFFLAGS, &ifr) == -1) {
return -1;
}
dev->flags = ifr.ifr_flags;
return 0;
}
int
tuntap_down(struct device *dev) {
struct ifreq ifr;
(void)memset(&ifr, '\0', sizeof ifr);
(void)memcpy(ifr.ifr_name, dev->if_name, sizeof dev->if_name);
ifr.ifr_flags = (short)dev->flags;
ifr.ifr_flags &= ~IFF_UP;
if (ioctl(dev->ctrl_sock, SIOCSIFFLAGS, &ifr) == -1) {
return -1;
}
dev->flags = ifr.ifr_flags;
return 0;
}
int
tuntap_get_mtu(struct device *dev) {
struct ifreq ifr;
/* Only accept started device */ /* Only accept started device */
if (dev->tun_fd == -1) if (dev->tun_fd == TUNFD_INVALID_VALUE) {
tuntap_log(TUNTAP_LOG_NOTICE, "Device is not started");
return 0; return 0;
(void)memset(&ifr, '\0', sizeof ifr);
(void)memcpy(ifr.ifr_name, dev->if_name, sizeof dev->if_name);
if (ioctl(dev->ctrl_sock, SIOCGIFMTU, &ifr) == -1) {
return -1;
}
return ifr.ifr_mtu;
}
int
tuntap_set_mtu(struct device *dev, int mtu) {
struct ifreq ifr;
/* Only accept started device */
if (dev->tun_fd == -1)
return 0;
(void)memset(&ifr, '\0', sizeof ifr);
(void)memcpy(ifr.ifr_name, dev->if_name, sizeof dev->if_name);
ifr.ifr_mtu = mtu;
if (ioctl(dev->ctrl_sock, SIOCSIFMTU, &ifr) == -1) {
return -1;
}
return 0;
}
int
tuntap_set_ip(struct device *dev, const char *saddr, int bits) {
struct sockaddr_in sa;
unsigned int addr;
unsigned int mask;
if (saddr == NULL) {
(void)fprintf(stderr, "libtuntap: tuntap_set_ip"
" invalid address\n");
return -1;
} }
if (bits < 0 || bits > 128) { if (addr == NULL) {
(void)fprintf(stderr, "libtuntap: tuntap_set_ip" tuntap_log(TUNTAP_LOG_ERR, "Invalid parameter 'addr'");
" invalid netmask\n");
return -1; return -1;
} }
/* Destination address */ if (netmask < 0 || netmask > 128) {
if (inet_pton(AF_INET, saddr, &(sa.sin_addr)) != 1) { tuntap_log(TUNTAP_LOG_ERR, "Invalid parameter 'netmask'");
(void)fprintf(stderr, "libtuntap: tuntap_set_ip (IPv4)"
" bad address\n");
return -1; return -1;
} }
addr = sa.sin_addr.s_addr;
/* Netmask */ /* Netmask */
mask = ~0; mask = ~0;
mask = ~(mask >> bits); mask = ~(mask >> netmask);
mask = ntohl(mask); mask = htonl(mask);
return tuntap_sys_set_ip(dev, addr, mask); /*
} * Destination address parsing: we try IPv4 first and fall back to
* IPv6 if inet_pton return 0
int */
tuntap_read(struct device *dev, void *buf, size_t size) { (void)memset(&baddr4, '\0', sizeof baddr4);
int n; (void)memset(&baddr6, '\0', sizeof baddr6);
/* Only accept started device */ errval = inet_pton(AF_INET, addr, &(baddr4));
if (dev->tun_fd == -1) if (errval == 1) {
return 0; return tuntap_sys_set_ipv4(dev, &baddr4, mask);
} else if (errval == 0) {
n = read(dev->tun_fd, buf, size); if (inet_pton(AF_INET6, addr, &(baddr6)) == -1) {
if (n == -1) { tuntap_log(TUNTAP_LOG_ERR, "Invalid parameters");
(void)fprintf(stderr, return -1;
"libtuntap: enable to read from device\n"); }
return tuntap_sys_set_ipv6(dev, &baddr6, mask);
} else if (errval == -1) {
tuntap_log(TUNTAP_LOG_ERR, "Invalid parameters");
return -1; return -1;
} }
return n;
}
int
tuntap_write(struct device *dev, void *buf, size_t size) {
int n;
/* Only accept started device */
if (dev->tun_fd == -1)
return 0;
n = write(dev->tun_fd, buf, size); /* NOTREACHED */
if (n == -1) { return -1;
(void)fprintf(stderr,
"libtuntap: enable to write to device\n");
return -1;
}
return n;
} }
 End of changes. 22 change blocks. 
209 lines changed or deleted 45 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/