#include <sys/socket.h>
|
#include <sys/select.h>
|
#include <sys/types.h>
|
#include <net/if.h>
|
#include <sys/socket.h>
|
#include <netinet/in.h>
|
#include <arpa/inet.h>
|
#include <endian.h>
|
|
#include "libmnl/ifutils.h"
|
#include "libmnl/dhcp/dhcp.h"
|
#include "util.h"
|
#include "QMIThread.h"
|
|
static int ql_raw_ip_mode_check(const char *ifname)
|
{
|
int fd;
|
char raw_ip[128];
|
char mode[2] = "X";
|
int mode_change = 0;
|
|
snprintf(raw_ip, sizeof(raw_ip), "/sys/class/net/%s/qmi/raw_ip", ifname);
|
if (access(raw_ip, F_OK))
|
return 0;
|
|
fd = open(raw_ip, O_RDWR | O_NONBLOCK | O_NOCTTY);
|
if (fd < 0)
|
{
|
dbg_time("%s %d fail to open(%s), errno:%d (%s)", __FILE__, __LINE__, raw_ip, errno, strerror(errno));
|
return 0;
|
}
|
|
read(fd, mode, 2);
|
if (mode[0] == '0' || mode[0] == 'N')
|
{
|
if_link_down(ifname);
|
dbg_time("echo Y > /sys/class/net/%s/qmi/raw_ip", ifname);
|
mode[0] = 'Y';
|
write(fd, mode, 2);
|
mode_change = 1;
|
if_link_up(ifname);
|
}
|
|
close(fd);
|
return mode_change;
|
}
|
|
void ql_set_driver_link_state(PROFILE_T *profile, int link_state)
|
{
|
char link_file[128];
|
int fd;
|
int new_state = 0;
|
|
snprintf(link_file, sizeof(link_file), "/sys/class/net/%s/link_state", profile->usbnet_adapter);
|
fd = open(link_file, O_RDWR | O_NONBLOCK | O_NOCTTY);
|
if (fd == -1)
|
{
|
if (errno != ENOENT)
|
dbg_time("Fail to access %s, errno: %d (%s)", link_file, errno, strerror(errno));
|
return;
|
}
|
|
if (profile->qmap_mode <= 1)
|
new_state = !!link_state;
|
else
|
{
|
//0x80 means link off this pdp
|
new_state = (link_state ? 0x00 : 0x80) + profile->pdp;
|
}
|
|
snprintf(link_file, sizeof(link_file), "%d\n", new_state);
|
write(fd, link_file, sizeof(link_file));
|
|
if (link_state == 0 && profile->qmap_mode > 1)
|
{
|
size_t rc;
|
|
lseek(fd, 0, SEEK_SET);
|
rc = read(fd, link_file, sizeof(link_file));
|
if (rc > 1 && (!strcasecmp(link_file, "0\n") || !strcasecmp(link_file, "0x0\n")))
|
{
|
if_link_down(profile->usbnet_adapter);
|
}
|
}
|
|
close(fd);
|
}
|
|
void udhcpc_start(PROFILE_T *profile)
|
{
|
char *ifname = profile->usbnet_adapter;
|
|
ql_set_driver_link_state(profile, 1);
|
ql_raw_ip_mode_check(ifname);
|
|
if (profile->qmapnet_adapter)
|
{
|
ifname = profile->qmapnet_adapter;
|
}
|
if (profile->rawIP && profile->ipv4.Address && profile->ipv4.Mtu)
|
{
|
if_set_mtu(ifname, (profile->ipv4.Mtu));
|
}
|
|
if (strcmp(ifname, profile->usbnet_adapter))
|
{
|
if_link_up(profile->usbnet_adapter);
|
}
|
|
if_link_up(ifname);
|
|
#if 1 //for bridge mode, only one public IP, so do udhcpc manually
|
if (ql_bridge_mode_detect(profile))
|
{
|
return;
|
}
|
#endif
|
// if use DHCP(should make with ${DHCP} src files)
|
// do_dhcp(ifname);
|
// return 0;
|
/* IPv4 Addr Info */
|
if (profile->ipv4.Address)
|
{
|
dbg_time("IPv4 MTU: %d", profile->ipv4.Mtu);
|
dbg_time("IPv4 Address: %s", ipaddr_to_string_v4(ntohl(profile->ipv4.Address)));
|
dbg_time("IPv4 Netmask: %d", mask_to_prefix_v4(ntohl(profile->ipv4.SubnetMask)));
|
dbg_time("IPv4 Gateway: %s", ipaddr_to_string_v4(ntohl(profile->ipv4.Gateway)));
|
dbg_time("IPv4 DNS1: %s", ipaddr_to_string_v4(ntohl(profile->ipv4.DnsPrimary)));
|
dbg_time("IPv4 DNS2: %s", ipaddr_to_string_v4(ntohl(profile->ipv4.DnsSecondary)));
|
if_set_network_v4(ifname, ntohl(profile->ipv4.Address),
|
mask_to_prefix_v4(profile->ipv4.SubnetMask),
|
ntohl(profile->ipv4.Gateway),
|
ntohl(profile->ipv4.DnsPrimary),
|
ntohl(profile->ipv4.DnsSecondary));
|
}
|
|
if (profile->ipv6.Address[0] && profile->ipv6.PrefixLengthIPAddr)
|
{
|
//module do not support DHCPv6, only support 'Router Solicit'
|
//and it seem if enable /proc/sys/net/ipv6/conf/all/forwarding, Kernel do not send RS
|
const char *forward_file = "/proc/sys/net/ipv6/conf/all/forwarding";
|
int forward_fd = open(forward_file, O_RDONLY);
|
if (forward_fd > 0)
|
{
|
char forward_state[2];
|
read(forward_fd, forward_state, 2);
|
if (forward_state[0] == '1')
|
{
|
dbg_time("%s enabled, kernel maybe donot send 'Router Solicit'", forward_file);
|
}
|
close(forward_fd);
|
}
|
|
dbg_time("IPv6 MTU: %d", profile->ipv6.Mtu);
|
dbg_time("IPv6 Address: %s", ipaddr_to_string_v6(profile->ipv6.Address));
|
dbg_time("IPv6 Netmask: %d", profile->ipv6.PrefixLengthIPAddr);
|
dbg_time("IPv6 Gateway: %s", ipaddr_to_string_v6(profile->ipv6.Gateway));
|
dbg_time("IPv6 DNS1: %s", ipaddr_to_string_v6(profile->ipv6.DnsPrimary));
|
dbg_time("IPv6 DNS2: %s", ipaddr_to_string_v6(profile->ipv6.DnsSecondary));
|
if_set_network_v6(ifname, profile->ipv6.Address, profile->ipv6.PrefixLengthIPAddr,
|
profile->ipv6.Gateway, profile->ipv6.DnsPrimary, profile->ipv6.DnsSecondary);
|
}
|
}
|
|
void udhcpc_stop(PROFILE_T *profile)
|
{
|
char *ifname = profile->usbnet_adapter;
|
|
ql_set_driver_link_state(profile, 0);
|
|
if (profile->qmapnet_adapter)
|
{
|
ifname = profile->qmapnet_adapter;
|
}
|
|
if_link_down(ifname);
|
if_flush_v4_addr(ifname);
|
if_flush_v6_addr(ifname);
|
}
|