1 #include <sys/socket.h>
2 #include <sys/select.h>
3 #include <sys/types.h>
4 #include <net/if.h>
5 #include <sys/socket.h>
6 #include <netinet/in.h>
7 #include <arpa/inet.h>
8 #include <endian.h>
9
10 #include "libmnl/ifutils.h"
11 #include "libmnl/dhcp/dhcp.h"
12 #include "util.h"
13 #include "QMIThread.h"
14
ql_raw_ip_mode_check(const char * ifname)15 static int ql_raw_ip_mode_check(const char *ifname)
16 {
17 int fd;
18 char raw_ip[128];
19 char mode[2] = "X";
20 int mode_change = 0;
21
22 snprintf(raw_ip, sizeof(raw_ip), "/sys/class/net/%s/qmi/raw_ip", ifname);
23 if (access(raw_ip, F_OK))
24 return 0;
25
26 fd = open(raw_ip, O_RDWR | O_NONBLOCK | O_NOCTTY);
27 if (fd < 0)
28 {
29 dbg_time("%s %d fail to open(%s), errno:%d (%s)", __FILE__, __LINE__, raw_ip, errno, strerror(errno));
30 return 0;
31 }
32
33 read(fd, mode, 2);
34 if (mode[0] == '0' || mode[0] == 'N')
35 {
36 if_link_down(ifname);
37 dbg_time("echo Y > /sys/class/net/%s/qmi/raw_ip", ifname);
38 mode[0] = 'Y';
39 write(fd, mode, 2);
40 mode_change = 1;
41 if_link_up(ifname);
42 }
43
44 close(fd);
45 return mode_change;
46 }
47
ql_set_driver_link_state(PROFILE_T * profile,int link_state)48 void ql_set_driver_link_state(PROFILE_T *profile, int link_state)
49 {
50 char link_file[128];
51 int fd;
52 int new_state = 0;
53
54 snprintf(link_file, sizeof(link_file), "/sys/class/net/%s/link_state", profile->usbnet_adapter);
55 fd = open(link_file, O_RDWR | O_NONBLOCK | O_NOCTTY);
56 if (fd == -1)
57 {
58 if (errno != ENOENT)
59 dbg_time("Fail to access %s, errno: %d (%s)", link_file, errno, strerror(errno));
60 return;
61 }
62
63 if (profile->qmap_mode <= 1)
64 new_state = !!link_state;
65 else
66 {
67 //0x80 means link off this pdp
68 new_state = (link_state ? 0x00 : 0x80) + profile->pdp;
69 }
70
71 snprintf(link_file, sizeof(link_file), "%d\n", new_state);
72 write(fd, link_file, sizeof(link_file));
73
74 if (link_state == 0 && profile->qmap_mode > 1)
75 {
76 size_t rc;
77
78 lseek(fd, 0, SEEK_SET);
79 rc = read(fd, link_file, sizeof(link_file));
80 if (rc > 1 && (!strcasecmp(link_file, "0\n") || !strcasecmp(link_file, "0x0\n")))
81 {
82 if_link_down(profile->usbnet_adapter);
83 }
84 }
85
86 close(fd);
87 }
88
udhcpc_start(PROFILE_T * profile)89 void udhcpc_start(PROFILE_T *profile)
90 {
91 char *ifname = profile->usbnet_adapter;
92
93 ql_set_driver_link_state(profile, 1);
94 ql_raw_ip_mode_check(ifname);
95
96 if (profile->qmapnet_adapter)
97 {
98 ifname = profile->qmapnet_adapter;
99 }
100 if (profile->rawIP && profile->ipv4.Address && profile->ipv4.Mtu)
101 {
102 if_set_mtu(ifname, (profile->ipv4.Mtu));
103 }
104
105 if (strcmp(ifname, profile->usbnet_adapter))
106 {
107 if_link_up(profile->usbnet_adapter);
108 }
109
110 if_link_up(ifname);
111
112 #if 1 //for bridge mode, only one public IP, so do udhcpc manually
113 if (ql_bridge_mode_detect(profile))
114 {
115 return;
116 }
117 #endif
118 // if use DHCP(should make with ${DHCP} src files)
119 // do_dhcp(ifname);
120 // return 0;
121 /* IPv4 Addr Info */
122 if (profile->ipv4.Address)
123 {
124 dbg_time("IPv4 MTU: %d", profile->ipv4.Mtu);
125 dbg_time("IPv4 Address: %s", ipaddr_to_string_v4(ntohl(profile->ipv4.Address)));
126 dbg_time("IPv4 Netmask: %d", mask_to_prefix_v4(ntohl(profile->ipv4.SubnetMask)));
127 dbg_time("IPv4 Gateway: %s", ipaddr_to_string_v4(ntohl(profile->ipv4.Gateway)));
128 dbg_time("IPv4 DNS1: %s", ipaddr_to_string_v4(ntohl(profile->ipv4.DnsPrimary)));
129 dbg_time("IPv4 DNS2: %s", ipaddr_to_string_v4(ntohl(profile->ipv4.DnsSecondary)));
130 if_set_network_v4(ifname, ntohl(profile->ipv4.Address),
131 mask_to_prefix_v4(profile->ipv4.SubnetMask),
132 ntohl(profile->ipv4.Gateway),
133 ntohl(profile->ipv4.DnsPrimary),
134 ntohl(profile->ipv4.DnsSecondary));
135 }
136
137 if (profile->ipv6.Address[0] && profile->ipv6.PrefixLengthIPAddr)
138 {
139 //module do not support DHCPv6, only support 'Router Solicit'
140 //and it seem if enable /proc/sys/net/ipv6/conf/all/forwarding, Kernel do not send RS
141 const char *forward_file = "/proc/sys/net/ipv6/conf/all/forwarding";
142 int forward_fd = open(forward_file, O_RDONLY);
143 if (forward_fd > 0)
144 {
145 char forward_state[2];
146 read(forward_fd, forward_state, 2);
147 if (forward_state[0] == '1')
148 {
149 dbg_time("%s enabled, kernel maybe donot send 'Router Solicit'", forward_file);
150 }
151 close(forward_fd);
152 }
153
154 dbg_time("IPv6 MTU: %d", profile->ipv6.Mtu);
155 dbg_time("IPv6 Address: %s", ipaddr_to_string_v6(profile->ipv6.Address));
156 dbg_time("IPv6 Netmask: %d", profile->ipv6.PrefixLengthIPAddr);
157 dbg_time("IPv6 Gateway: %s", ipaddr_to_string_v6(profile->ipv6.Gateway));
158 dbg_time("IPv6 DNS1: %s", ipaddr_to_string_v6(profile->ipv6.DnsPrimary));
159 dbg_time("IPv6 DNS2: %s", ipaddr_to_string_v6(profile->ipv6.DnsSecondary));
160 if_set_network_v6(ifname, profile->ipv6.Address, profile->ipv6.PrefixLengthIPAddr,
161 profile->ipv6.Gateway, profile->ipv6.DnsPrimary, profile->ipv6.DnsSecondary);
162 }
163 }
164
udhcpc_stop(PROFILE_T * profile)165 void udhcpc_stop(PROFILE_T *profile)
166 {
167 char *ifname = profile->usbnet_adapter;
168
169 ql_set_driver_link_state(profile, 0);
170
171 if (profile->qmapnet_adapter)
172 {
173 ifname = profile->qmapnet_adapter;
174 }
175
176 if_link_down(ifname);
177 if_flush_v4_addr(ifname);
178 if_flush_v6_addr(ifname);
179 }
180