net_tun library is updated for supporting FreeBSD and MacOSX

In FreeBSD and MacOSX, tun driver is automatically configured.
This commit is contained in:
Sukchan Lee 2017-10-17 07:03:37 +09:00
parent 86908cdbe9
commit b8a37b0ea1
3 changed files with 154 additions and 66 deletions

View File

@ -263,12 +263,10 @@ CORE_DECLARE(int) net_unregister_link(net_link_t *net_link);
CORE_DECLARE(int) net_fds_read_run(long timeout);
/** TunTap interface */
CORE_DECLARE(int) net_tuntap_open(net_link_t **net_link, char *tuntap_dev_name,
int is_tap);
CORE_DECLARE(int) net_tuntap_set_ipv4(c_uint32_t ip_addr, c_uint8_t bits);
CORE_DECLARE(int) net_tuntap_close(net_link_t *net_link);
CORE_DECLARE(int) net_tun_open(net_link_t **net_link, char *name, int is_tap);
CORE_DECLARE(int) net_tun_set_ipv4(
net_link_t *net_link, c_uint32_t addr, c_uint8_t bits);
CORE_DECLARE(int) net_tun_close(net_link_t *net_link);
#ifdef __cplusplus
}

View File

@ -1171,6 +1171,7 @@ int net_raw_open(net_link_t **net_link, int proto)
}
/** Create tuntap socket */
#if 0 /* deprecated */
int net_tuntap_open(net_link_t **net_link, char *tuntap_dev_name,
int is_tap)
{
@ -1224,35 +1225,96 @@ cleanup:
return -1;
#endif
}
#endif
int net_tuntap_set_ipv4(c_uint32_t ip_addr, c_uint8_t bits)
/** Create tun socket */
int net_tun_open(net_link_t **net_link, char *ifname, int is_tap)
{
int sock;
net_link_t *new_link = NULL;
#if LINUX == 1
/* No root priviledge */
char *dev = "/dev/net/tun";
int rc;
struct ifreq ifr;
int flags = IFF_NO_PI;
sock = open(dev, O_RDWR);
if (sock < 0)
{
d_error("Can not open %s",dev);
return -1;
}
#else
char name[C_PATH_MAX];
int tun = 0;
#define TUNTAP_ID_MAX 255
for (tun = 0; tun < TUNTAP_ID_MAX; tun++)
{
(void)snprintf(name, sizeof(name), "/dev/tun%i", tun);
if ((sock = open(name, O_RDWR)) > 0)
{
(void)snprintf(name, sizeof(name), "tun%i", tun);
ifname = name;
break;
}
}
#endif
pool_alloc_node(&link_pool, &new_link);
d_assert(new_link != NULL, return -1,"No link pool is availabe\n");
#if LINUX == 1
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = (is_tap ? (flags | IFF_TAP) : (flags | IFF_TUN));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
rc = ioctl(sock, TUNSETIFF, (void *)&ifr);
if (rc < 0)
{
d_error("iotcl error(dev:%s flags = %d)", ifname, flags);
goto cleanup;
}
#endif
/* Save socket descriptor */
new_link->fd = sock;
/* Save the interface name */
strncpy(new_link->ifname, ifname, IFNAMSIZ);
*net_link = new_link;
return 0;
#elif defined(DARWIN)
#if LINUX == 1
cleanup:
pool_free_node(&link_pool, new_link);
close(sock);
return -1;
#endif
}
int net_tun_set_ipv4(net_link_t *link, c_uint32_t ip_addr, c_uint8_t bits)
{
#if LINUX != 1
c_uint32_t mask_addr = htonl(0xffffffff << (32 - bits));
int sock = socket(AF_INET, SOCK_DGRAM, 0);
char *dev = "tun0";
struct ifaliasreq ifa;
struct ifreq ifr;
struct sockaddr_in addr;
struct sockaddr_in mask;
(void)memset(&ifa, '\0', sizeof ifa);
(void)strlcpy(ifa.ifra_name, dev, sizeof ifa.ifra_name);
(void)strlcpy(ifa.ifra_name, link->ifname, sizeof ifa.ifra_name);
(void)memset(&ifr, '\0', sizeof ifr);
(void)strlcpy(ifr.ifr_name, dev, sizeof ifr.ifr_name);
(void)strlcpy(ifr.ifr_name, link->ifname, sizeof ifr.ifr_name);
/* Delete previously assigned address */
(void)ioctl(sock, SIOCDIFADDR, &ifr);
/*
* Fill-in the destination address and netmask,
* but don't care of the broadcast address
*/
#if defined(DARWIN)
(void)memset(&addr, '\0', sizeof addr);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ip_addr;
@ -1273,16 +1335,41 @@ int net_tuntap_set_ipv4(c_uint32_t ip_addr, c_uint8_t bits)
(void)memcpy(&ifr.ifr_addr, &addr, sizeof addr);
if (ioctl(sock, SIOCSIFDSTADDR, &ifr) == -1) {
d_error("Can't set IP/netmask");
d_error("Can't set dst IP/netmask");
return -1;
}
#else
(void)memset(&addr, '\0', sizeof addr);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ip_addr;
addr.sin_len = sizeof addr;
(void)memcpy(&ifa.ifra_addr, &addr, sizeof addr);
(void)memcpy(&ifa.ifra_broadaddr, &addr, sizeof addr);
(void)memset(&mask, '\0', sizeof mask);
mask.sin_family = AF_INET;
mask.sin_addr.s_addr = mask_addr;
mask.sin_len = sizeof mask;
(void)memcpy(&ifa.ifra_mask, &mask, sizeof ifa.ifra_mask);
(void)memset(&addr, '\0', sizeof addr);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ip_addr;
addr.sin_len = sizeof addr;
(void)memcpy(&ifr.ifr_addr, &addr, sizeof addr);
if (ioctl(sock, SIOCAIFADDR, &ifa) == -1) {
d_error("Can't src IP address(dev:%s err:%s)",
link->ifname, strerror(errno));
return -1;
}
#endif /* !defined(DARWIN) */
close(sock);
#endif /* LINUX == 1 */
return 0;
#else
/* TODO */
return 0;
#endif /* LINUX != 1 */
}
@ -1431,7 +1518,7 @@ int net_raw_close(net_link_t *net_link)
return 0;
}
int net_tuntap_close(net_link_t *net_link)
int net_tun_close(net_link_t *net_link)
{
d_assert(net_link,return -1, "net_link is NULL\n");
close(net_link->fd);

View File

@ -173,6 +173,8 @@ static int _gtpv1_u_recv_cb(net_sock_t *sock, void *data)
status_t pgw_gtp_open()
{
status_t rv;
int rc;
char buf[INET_ADDRSTRLEN];
rv = gtp_listen(&pgw_self()->gtpc_sock, _gtpv2_c_recv_cb,
pgw_self()->gtpc_addr, pgw_self()->gtpc_port, NULL);
@ -190,52 +192,53 @@ status_t pgw_gtp_open()
return rv;
}
/* NOTE : tun device can be created via following command.
*
* $ sudo ip tuntap add name pgwtun mode tun
*
* Also, before running pgw, assign the one IP from IP pool of UE
* to pgwtun. The IP should not be assigned to UE
*
* $ sudo ifconfig pgwtun 45.45.0.1/16 up
*
*/
/* Open Tun interface */
rc = net_tun_open(&pgw_self()->tun_link, pgw_self()->tun_dev_name, 0);
if (rc != 0)
{
int rc;
int i;
char buf[INET_ADDRSTRLEN];
d_error("Can not open tun(dev : %s)", pgw_self()->tun_dev_name);
return CORE_ERROR;
}
/* NOTE : tun device can be created via following command.
*
* $ sudo ip tuntap add name pgwtun mode tun
*
* Also, before running pgw, assign the one IP from IP pool of UE
* to pgwtun. The IP should not be assigned to UE
*
* $ sudo ifconfig pgwtun 45.45.0.1/16 up
*
*/
/*
* On Linux, it is possible to create a persistent tun/tap
* interface which will continue to exist even if nextepc quit,
* although this is normally not required.
* It can be useful to set up a tun/tap interface owned
* by a non-root user, so nextepc can be started without
* needing any root privileges at all.
*/
/* Open Tun interface */
rc = net_tuntap_open(&pgw_self()->tun_link, pgw_self()->tun_dev_name, 0);
if (rc != 0)
{
d_error("Can not open tun(dev : %s)", pgw_self()->tun_dev_name);
return CORE_ERROR;
}
for (i = 0; i < pgw_self()->num_of_ip_pool; i++)
{
rc = net_tuntap_set_ipv4(
pgw_self()->ip_pool[i].prefix, pgw_self()->ip_pool[i].mask);
if (rc != 0)
{
d_error("Can not configure tun(dev : %s for %s/%d)",
pgw_self()->tun_dev_name,
INET_NTOP(&pgw_self()->ip_pool[i].prefix, buf),
pgw_self()->ip_pool[i].mask);
return CORE_ERROR;
}
}
rc = net_register_link(pgw_self()->tun_link, _gtpv1_tun_recv_cb, NULL);
if (rc != 0)
{
d_error("Can not register tun(dev : %s)", pgw_self()->tun_dev_name);
net_tuntap_close(pgw_self()->tun_link);
return CORE_ERROR;
}
/* Set P-to-P IP address with Netmask
* Note that Linux will skip this configuration */
rc = net_tun_set_ipv4(pgw_self()->tun_link,
pgw_self()->ip_pool[0].prefix, pgw_self()->ip_pool[0].mask);
if (rc != 0)
{
d_error("Can not configure tun(dev : %s for %s/%d)",
pgw_self()->tun_dev_name,
INET_NTOP(&pgw_self()->ip_pool[0].prefix, buf),
pgw_self()->ip_pool[0].mask);
return CORE_ERROR;
}
rc = net_register_link(pgw_self()->tun_link, _gtpv1_tun_recv_cb, NULL);
if (rc != 0)
{
d_error("Can not register tun(dev : %s)", pgw_self()->tun_dev_name);
net_tun_close(pgw_self()->tun_link);
return CORE_ERROR;
}
return CORE_OK;
@ -260,7 +263,7 @@ status_t pgw_gtp_close()
}
net_unregister_link(pgw_self()->tun_link);
net_tuntap_close(pgw_self()->tun_link);
net_tun_close(pgw_self()->tun_link);
return CORE_OK;
}