1 /******************************************************************************
2 @file udhcpc.c
3 @brief call DHCP tools to obtain IP address.
4
5 DESCRIPTION
6 Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
7
8 INITIALIZATION AND SEQUENCING REQUIREMENTS
9 None.
10
11 ---------------------------------------------------------------------------
12 Copyright (c) 2016 - 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
13 Quectel Wireless Solution Proprietary and Confidential.
14 ---------------------------------------------------------------------------
15 ******************************************************************************/
16 #include <sys/socket.h>
17 #include <sys/select.h>
18 #include <sys/types.h>
19 #include <net/if.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <endian.h>
24
25 #include "util.h"
26 #include "QMIThread.h"
27
qmi2addr(uint32_t __x)28 static __inline in_addr_t qmi2addr(uint32_t __x) {
29 return (__x>>24) | (__x>>8&0xff00) | (__x<<8&0xff0000) | (__x<<24);
30 }
31
ql_system(const char * shell_cmd)32 static int ql_system(const char *shell_cmd) {
33 dbg_time("%s", shell_cmd);
34 return system(shell_cmd);
35 }
36
ifc_init_ifr(const char * name,struct ifreq * ifr)37 static void ifc_init_ifr(const char *name, struct ifreq *ifr)
38 {
39 memset(ifr, 0, sizeof(struct ifreq));
40 strncpy(ifr->ifr_name, name, IFNAMSIZ);
41 ifr->ifr_name[IFNAMSIZ - 1] = 0;
42 }
43
ql_set_mtu(const char * ifname,int ifru_mtu)44 static void ql_set_mtu(const char *ifname, int ifru_mtu) {
45 int inet_sock;
46 struct ifreq ifr;
47
48 inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
49
50 if (inet_sock > 0) {
51 ifc_init_ifr(ifname, &ifr);
52
53 if (!ioctl(inet_sock, SIOCGIFMTU, &ifr)) {
54 if (ifr.ifr_ifru.ifru_mtu != ifru_mtu) {
55 dbg_time("change mtu %d -> %d", ifr.ifr_ifru.ifru_mtu , ifru_mtu);
56 ifr.ifr_ifru.ifru_mtu = ifru_mtu;
57 ioctl(inet_sock, SIOCSIFMTU, &ifr);
58 }
59 }
60
61 close(inet_sock);
62 }
63 }
64
ifc_get_addr(const char * name,in_addr_t * addr)65 static int ifc_get_addr(const char *name, in_addr_t *addr)
66 {
67 int inet_sock;
68 struct ifreq ifr;
69 int ret = 0;
70
71 inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
72
73 ifc_init_ifr(name, &ifr);
74 if (addr != NULL) {
75 ret = ioctl(inet_sock, SIOCGIFADDR, &ifr);
76 if (ret < 0) {
77 *addr = 0;
78 } else {
79 *addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
80 }
81 }
82 close(inet_sock);
83 return ret;
84 }
85
ifc_get_flags(const char * ifname)86 static short ifc_get_flags(const char *ifname)
87 {
88 int inet_sock;
89 struct ifreq ifr;
90 int ret = 0;
91
92 inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
93
94 if (inet_sock > 0) {
95 ifc_init_ifr(ifname, &ifr);
96
97 if (!ioctl(inet_sock, SIOCGIFFLAGS, &ifr)) {
98 ret = ifr.ifr_ifru.ifru_flags;
99 }
100
101 close(inet_sock);
102 }
103
104 return ret;
105 }
106
ql_netcard_ipv4_address_check(const char * ifname,in_addr_t ip)107 static int ql_netcard_ipv4_address_check(const char *ifname, in_addr_t ip) {
108 in_addr_t addr = 0;
109
110 ifc_get_addr(ifname, &addr);
111 return addr == ip;
112 }
113
ql_raw_ip_mode_check(const char * ifname,uint32_t ip)114 static int ql_raw_ip_mode_check(const char *ifname, uint32_t ip) {
115 int fd;
116 char raw_ip[128];
117 char shell_cmd[128];
118 char mode[2] = "X";
119 int mode_change = 0;
120
121 if (ql_netcard_ipv4_address_check(ifname, qmi2addr(ip)))
122 return 0;
123
124 snprintf(raw_ip, sizeof(raw_ip), "/sys/class/net/%s/qmi/raw_ip", ifname);
125 if (access(raw_ip, F_OK))
126 return 0;
127
128 fd = open(raw_ip, O_RDWR | O_NONBLOCK | O_NOCTTY);
129 if (fd < 0) {
130 dbg_time("%s %d fail to open(%s), errno:%d (%s)", __FILE__, __LINE__, raw_ip, errno, strerror(errno));
131 return 0;
132 }
133
134 if (read(fd, mode, 2) == -1) {};
135 if (mode[0] == '0' || mode[0] == 'N') {
136 dbg_time("File:%s Line:%d udhcpc fail to get ip address, try next:", __func__, __LINE__);
137 snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s down", ifname);
138 ql_system(shell_cmd);
139 dbg_time("echo Y > /sys/class/net/%s/qmi/raw_ip", ifname);
140 mode[0] = 'Y';
141 if (write(fd, mode, 2) == -1) {};
142 mode_change = 1;
143 snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s up", ifname);
144 ql_system(shell_cmd);
145 }
146
147 close(fd);
148 return mode_change;
149 }
150
udhcpc_thread_function(void * arg)151 static void* udhcpc_thread_function(void* arg) {
152 FILE * udhcpc_fp;
153 char *udhcpc_cmd = (char *)arg;
154
155 if (udhcpc_cmd == NULL)
156 return NULL;
157
158 dbg_time("%s", udhcpc_cmd);
159 udhcpc_fp = popen(udhcpc_cmd, "r");
160 free(udhcpc_cmd);
161 if (udhcpc_fp) {
162 char buf[0xff];
163
164 buf[sizeof(buf)-1] = '\0';
165 while((fgets(buf, sizeof(buf)-1, udhcpc_fp)) != NULL) {
166 if ((strlen(buf) > 1) && (buf[strlen(buf) - 1] == '\n'))
167 buf[strlen(buf) - 1] = '\0';
168 dbg_time("%s", buf);
169 }
170
171 pclose(udhcpc_fp);
172 }
173
174 return NULL;
175 }
176
177 //#define USE_DHCLIENT
178 #ifdef USE_DHCLIENT
179 static int dhclient_alive = 0;
180 #endif
181 static int dibbler_client_alive = 0;
182
ql_set_driver_link_state(PROFILE_T * profile,int link_state)183 void ql_set_driver_link_state(PROFILE_T *profile, int link_state) {
184 char link_file[128];
185 int fd;
186 int new_state = 0;
187
188 snprintf(link_file, sizeof(link_file), "/sys/class/net/%s/link_state", profile->usbnet_adapter);
189 fd = open(link_file, O_RDWR | O_NONBLOCK | O_NOCTTY);
190 if (fd == -1) {
191 if (errno != ENOENT)
192 dbg_time("Fail to access %s, errno: %d (%s)", link_file, errno, strerror(errno));
193 return;
194 }
195
196 if (profile->qmap_mode <= 1)
197 new_state = !!link_state;
198 else {
199 //0x80 means link off this pdp
200 new_state = (link_state ? 0x00 : 0x80) + (profile->muxid - 0x80);
201 }
202
203 snprintf(link_file, sizeof(link_file), "%d\n", new_state);
204 if (write(fd, link_file, sizeof(link_file)) == -1) {};
205
206 if (link_state == 0 && profile->qmapnet_adapter[0]
207 && strcmp(profile->qmapnet_adapter, profile->usbnet_adapter)) {
208 size_t rc;
209
210 lseek(fd, 0, SEEK_SET);
211 rc = read(fd, link_file, sizeof(link_file));
212 if (rc > 1 && (!strncasecmp(link_file, "0\n", 2) || !strncasecmp(link_file, "0x0\n", 4))) {
213 snprintf(link_file, sizeof(link_file), "ifconfig %s down", profile->usbnet_adapter);
214 ql_system(link_file);
215 }
216 }
217
218 close(fd);
219 }
220
ipv4Str(const uint32_t Address)221 static const char *ipv4Str(const uint32_t Address) {
222 static char str[] = {"255.225.255.255"};
223 uint8_t *ip = (uint8_t *)&Address;
224
225 snprintf(str, sizeof(str), "%d.%d.%d.%d", ip[3], ip[2], ip[1], ip[0]);
226 return str;
227 }
228
ipv6Str(const UCHAR Address[16])229 static const char *ipv6Str(const UCHAR Address[16]) {
230 static char str[64];
231 uint16_t ip[8];
232 int i;
233 for (i = 0; i < 8; i++) {
234 ip[i] = (Address[i*2]<<8) + Address[i*2+1];
235 }
236
237 snprintf(str, sizeof(str), "%x:%x:%x:%x:%x:%x:%x:%x",
238 ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]);
239
240 return str;
241 }
242
update_ipv4_address(const char * ifname,const char * ip,const char * gw,unsigned prefix)243 void update_ipv4_address(const char *ifname, const char *ip, const char *gw, unsigned prefix)
244 {
245 char shell_cmd[128];
246
247 if (!ifname)
248 return;
249
250 if (!access("/sbin/ip", X_OK)) {
251 snprintf(shell_cmd, sizeof(shell_cmd), "ip -%d address flush dev %s", 4, ifname);
252 ql_system(shell_cmd);
253
254 snprintf(shell_cmd, sizeof(shell_cmd), "ip -%d address add %s/%u dev %s", 4, ip, prefix, ifname);
255 ql_system(shell_cmd);
256
257 //ping6 www.qq.com
258 snprintf(shell_cmd, sizeof(shell_cmd), "ip -%d route add default via %s dev %s", 4, gw, ifname);
259 ql_system(shell_cmd);
260 } else {
261 unsigned n = (0xFFFFFFFF >> (32 - prefix)) << (32 - prefix);
262 n = (n>>24) | (n>>8&0xff00) | (n<<8&0xff0000) | (n<<24);
263
264 snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s %s netmask %s", ifname, ip, ipv4Str(n));
265 ql_system(shell_cmd);
266
267 //Resetting default routes
268 snprintf(shell_cmd, sizeof(shell_cmd), "route del default dev %s", ifname);
269 while(!system(shell_cmd));
270
271 snprintf(shell_cmd, sizeof(shell_cmd), "route add default gw %s dev %s", gw, ifname);
272 ql_system(shell_cmd);
273 }
274 }
275
update_ipv6_address(const char * ifname,const char * ip,const char * gw,unsigned prefix)276 void update_ipv6_address(const char *ifname, const char *ip, const char *gw, unsigned prefix) {
277 char shell_cmd[128];
278
279 (void)gw;
280 if (!access("/sbin/ip", X_OK)) {
281 snprintf(shell_cmd, sizeof(shell_cmd), "ip -%d address flush dev %s", 6, ifname);
282 ql_system(shell_cmd);
283
284 snprintf(shell_cmd, sizeof(shell_cmd), "ip -%d address add %s/%u dev %s", 6, ip, prefix, ifname);
285 ql_system(shell_cmd);
286
287 //ping6 www.qq.com
288 snprintf(shell_cmd, sizeof(shell_cmd), "ip -%d route add default dev %s", 6, ifname);
289 ql_system(shell_cmd);
290 } else {
291 snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s %s/%d", ifname, ip, prefix);
292 ql_system(shell_cmd);
293
294 snprintf(shell_cmd, sizeof(shell_cmd), "route -A inet6 add default dev %s", ifname);
295 ql_system(shell_cmd);
296 }
297 }
298
update_ip_address_by_qmi(const char * ifname,const IPV4_T * ipv4,const IPV6_T * ipv6)299 static void update_ip_address_by_qmi(const char *ifname, const IPV4_T *ipv4, const IPV6_T *ipv6) {
300 char *d1, *d2;
301
302 if (ipv4 && ipv4->Address) {
303 d1 = strdup(ipv4Str(ipv4->Address));
304 d2 = strdup(ipv4Str(ipv4->Gateway));
305 unsigned prefix = 0;
306 unsigned n = 0;
307
308 for (n = 0; n < 32; n++) {
309 if (ipv4->SubnetMask&(1<<n)) {
310 prefix++;
311 }
312 }
313
314 update_ipv4_address(ifname, d1, d2, prefix);
315 free(d1); free(d2);
316
317 //Adding DNS
318 if (ipv4->DnsPrimary) {
319 d1 = strdup(ipv4Str(ipv4->DnsPrimary));
320 d2 = strdup(ipv4Str(ipv4->DnsSecondary ? ipv4->DnsSecondary : ipv4->DnsPrimary));
321 update_resolv_conf(4, ifname, d1, d2);
322 free(d1); free(d2);
323 }
324 }
325
326 if (ipv6 && ipv6->Address[0] && ipv6->PrefixLengthIPAddr) {
327 d1 = strdup(ipv6Str(ipv6->Address));
328 d2 = strdup(ipv6Str(ipv6->Gateway));
329
330 update_ipv6_address(ifname, d1, d2, ipv6->PrefixLengthIPAddr);
331 free(d1); free(d2);
332
333 //Adding DNS
334 if (ipv6->DnsPrimary[0]) {
335 d1 = strdup(ipv6Str(ipv6->DnsPrimary));
336 d2 = strdup(ipv6Str(ipv6->DnsSecondary[0] ? ipv6->DnsSecondary : ipv6->DnsPrimary));
337 update_resolv_conf(6, ifname, d1, d2);
338 free(d1); free(d2);
339 }
340 }
341 }
342
343 //#define QL_OPENWER_NETWORK_SETUP
344 #ifdef QL_OPENWER_NETWORK_SETUP
345 static const char *openwrt_lan = "br-lan";
346 static const char *openwrt_wan = "wwan0";
347
ql_openwrt_system(const char * cmd)348 static int ql_openwrt_system(const char *cmd) {
349 int i;
350 int ret = 1;
351 char shell_cmd[128];
352
353 snprintf(shell_cmd, sizeof(shell_cmd), "%s 2>1 > /dev/null", cmd);
354
355 for (i = 0; i < 15; i++) {
356 dbg_time("%s", cmd);
357 ret = system(shell_cmd);
358 if (!ret)
359 break;
360 sleep(1);
361 }
362
363 return ret;
364 }
365
ql_openwrt_is_wan(const char * ifname)366 static int ql_openwrt_is_wan(const char *ifname) {
367 if (openwrt_lan == NULL) {
368 system("uci show network.wan.ifname");
369 }
370
371 if (strcmp(ifname, openwrt_wan))
372 return 0;
373
374 return 1;
375 }
376
ql_openwrt_setup_wan(const char * ifname,const IPV4_T * ipv4)377 static void ql_openwrt_setup_wan(const char *ifname, const IPV4_T *ipv4) {
378 FILE *fp = NULL;
379 char config[64];
380
381 snprintf(config, sizeof(config), "/tmp/rmnet_%s_ipv4config", ifname);
382
383 if (ipv4 == NULL) {
384 if (ql_openwrt_is_wan(ifname))
385 ql_openwrt_system("ifdown wan");
386 return;
387 }
388
389 fp = fopen(config, "w");
390 if (fp == NULL)
391 return;
392
393 fprintf(fp, "IFNAME=\"%s\"\n", ifname);
394 fprintf(fp, "PUBLIC_IP=\"%s\"\n", ipv4Str(ipv4->Address));
395 fprintf(fp, "NETMASK=\"%s\"\n", ipv4Str(ipv4->SubnetMask));
396 fprintf(fp, "GATEWAY=\"%s\"\n", ipv4Str(ipv4->Gateway));
397 fprintf(fp, "DNSSERVERS=\"%s", ipv4Str(ipv4->DnsPrimary));
398 if (ipv4->DnsSecondary != 0)
399 fprintf(fp, " %s", ipv4Str(ipv4->DnsSecondary));
400 fprintf(fp, "\"\n");
401
402 fclose(fp);
403
404 if (!ql_openwrt_is_wan(ifname))
405 return;
406
407 ql_openwrt_system("ifup wan");
408 }
409
ql_openwrt_setup_wan6(const char * ifname,const IPV6_T * ipv6)410 static void ql_openwrt_setup_wan6(const char *ifname, const IPV6_T *ipv6) {
411 FILE *fp = NULL;
412 char config[64];
413 int first_ifup;
414
415 snprintf(config, sizeof(config), "/tmp/rmnet_%s_ipv6config", ifname);
416
417 if (ipv6 == NULL) {
418 if (ql_openwrt_is_wan(ifname))
419 ql_openwrt_system("ifdown wan6");
420 return;
421 }
422
423 first_ifup = (access(config, F_OK) != 0);
424
425 fp = fopen(config, "w");
426 if (fp == NULL)
427 return;
428
429 fprintf(fp, "IFNAME=\"%s\"\n", ifname);
430 fprintf(fp, "PUBLIC_IP=\"%s\"\n", ipv6Str(ipv6->Address));
431 fprintf(fp, "NETMASK=\"%s\"\n", ipv6Str(ipv6->SubnetMask));
432 fprintf(fp, "GATEWAY=\"%s\"\n", ipv6Str(ipv6->Gateway));
433 fprintf(fp, "PrefixLength=\"%d\"\n", ipv6->PrefixLengthIPAddr);
434 fprintf(fp, "DNSSERVERS=\"%s", ipv6Str(ipv6->DnsPrimary));
435 if (ipv6->DnsSecondary[0])
436 fprintf(fp, " %s", ipv6Str(ipv6->DnsSecondary));
437 fprintf(fp, "\"\n");
438
439 fclose(fp);
440
441 if (!ql_openwrt_is_wan(ifname))
442 return;
443
444 if (first_ifup)
445 ql_openwrt_system("ifup wan6");
446 else
447 ql_openwrt_system("/etc/init.d/network restart"); //make PC to release old IPV6 address, and RS new IPV6 address
448
449 #if 1 //TODO? why need this?
450 if (openwrt_lan) {
451 int i;
452 char shell_cmd[128];
453 UCHAR Address[16] = {0};
454
455 ql_openwrt_system(("ifstatus lan"));
456
457 for (i = 0; i < (ipv6->PrefixLengthIPAddr/8); i++)
458 Address[i] = ipv6->Address[i];
459
460 snprintf(shell_cmd, sizeof(shell_cmd), "ip route del %s/%u dev %s", ipv6Str(Address), ipv6->PrefixLengthIPAddr, ifname);
461 ql_openwrt_system(shell_cmd);
462
463 snprintf(shell_cmd, sizeof(shell_cmd), "ip route add %s/%u dev %s", ipv6Str(Address), ipv6->PrefixLengthIPAddr, openwrt_lan);
464 ql_system(shell_cmd);
465 }
466 #endif
467 }
468 #endif
469
udhcpc_start(PROFILE_T * profile)470 void udhcpc_start(PROFILE_T *profile) {
471 char *ifname = profile->usbnet_adapter;
472 char shell_cmd[128];
473
474 ql_set_driver_link_state(profile, 1);
475
476 if (profile->qmapnet_adapter[0]) {
477 ifname = profile->qmapnet_adapter;
478 }
479
480 if (profile->rawIP && profile->ipv4.Address && profile->ipv4.Mtu) {
481 ql_set_mtu(ifname, (profile->ipv4.Mtu));
482 }
483
484 if (strcmp(ifname, profile->usbnet_adapter)) {
485 snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s up", profile->usbnet_adapter);
486 ql_system(shell_cmd);
487 if (ifc_get_flags(ifname)&IFF_UP) {
488 snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s down", ifname);
489 ql_system(shell_cmd);
490 }
491 }
492
493 snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s up", ifname);
494 ql_system(shell_cmd);
495
496 if (profile->ipv4.Address) {
497 if (profile->PCSCFIpv4Addr1)
498 dbg_time("pcscf1: %s", ipv4Str(profile->PCSCFIpv4Addr1));
499 if (profile->PCSCFIpv4Addr2)
500 dbg_time("pcscf2: %s", ipv4Str(profile->PCSCFIpv4Addr2));
501 }
502
503 if (profile->ipv6.Address[0] && profile->ipv6.PrefixLengthIPAddr) {
504 if (profile->PCSCFIpv6Addr1[0])
505 dbg_time("pcscf1: %s", ipv6Str(profile->PCSCFIpv6Addr1));
506 if (profile->PCSCFIpv6Addr2[0])
507 dbg_time("pcscf2: %s", ipv6Str(profile->PCSCFIpv6Addr2));
508 }
509
510 #if 1 //for bridge mode, only one public IP, so do udhcpc manually
511 if (ql_bridge_mode_detect(profile)) {
512 return;
513 }
514 #endif
515
516 //because must use udhcpc to obtain IP when working on ETH mode,
517 //so it is better also use udhcpc to obtain IP when working on IP mode.
518 //use the same policy for all modules
519 #if 0
520 if (profile->rawIP != 0) //mdm9x07/ec25,ec20 R2.0
521 {
522 update_ip_address_by_qmi(ifname, &profile->ipv4, &profile->ipv6);
523 return;
524 }
525 #endif
526
527 if (profile->ipv4.Address == 0)
528 goto set_ipv6;
529
530 if (profile->request_ops == &mbim_request_ops) { //lots of mbim modem do not support DHCP
531 update_ip_address_by_qmi(ifname, &profile->ipv4, NULL);
532 }
533 else
534 /* Do DHCP using busybox tools */
535 {
536 char udhcpc_cmd[128];
537 pthread_attr_t udhcpc_thread_attr;
538 pthread_t udhcpc_thread_id;
539
540 pthread_attr_init(&udhcpc_thread_attr);
541 pthread_attr_setdetachstate(&udhcpc_thread_attr, PTHREAD_CREATE_DETACHED);
542
543 #ifdef USE_DHCLIENT
544 snprintf(udhcpc_cmd, sizeof(udhcpc_cmd), "dhclient -4 -d --no-pid %s", ifname);
545 dhclient_alive++;
546 #else
547 if (access("/usr/share/udhcpc/default.script", X_OK)
548 && access("/etc//udhcpc/default.script", X_OK)) {
549 dbg_time("No default.script found, it should be in '/usr/share/udhcpc/' or '/etc//udhcpc' depend on your udhcpc version!");
550 }
551
552 //-f,--foreground Run in foreground
553 //-b,--background Background if lease is not obtained
554 //-n,--now Exit if lease is not obtained
555 //-q,--quit Exit after obtaining lease
556 //-t,--retries N Send up to N discover packets (default 3)
557 snprintf(udhcpc_cmd, sizeof(udhcpc_cmd), "busybox udhcpc -f -n -q -t 5 -i %s", ifname);
558 #endif
559
560 #if 1 //for OpenWrt
561 if (!access("/lib/netifd/dhcp.script", X_OK) && !access("/sbin/ifup", X_OK) && !access("/sbin/ifstatus", X_OK)) {
562 dbg_time("you are use OpenWrt?");
563 dbg_time("should not calling udhcpc manually?");
564 dbg_time("should modify /etc/config/network as below?");
565 dbg_time("config interface wan");
566 dbg_time("\toption ifname %s", ifname);
567 dbg_time("\toption proto dhcp");
568 dbg_time("should use \"/sbin/ifstaus wan\" to check %s 's status?", ifname);
569 }
570 #endif
571
572 #ifdef USE_DHCLIENT
573 pthread_create(&udhcpc_thread_id, &udhcpc_thread_attr, udhcpc_thread_function, (void*)strdup(udhcpc_cmd));
574 sleep(1);
575 #else
576 pthread_create(&udhcpc_thread_id, NULL, udhcpc_thread_function, (void*)strdup(udhcpc_cmd));
577 pthread_join(udhcpc_thread_id, NULL);
578
579 if (profile->request_ops != &qmi_request_ops) { //only QMI modem support next fixup!
580 goto set_ipv6;
581 }
582
583 if (ql_raw_ip_mode_check(ifname, profile->ipv4.Address)) {
584 pthread_create(&udhcpc_thread_id, NULL, udhcpc_thread_function, (void*)strdup(udhcpc_cmd));
585 pthread_join(udhcpc_thread_id, NULL);
586 }
587
588 if (!ql_netcard_ipv4_address_check(ifname, qmi2addr(profile->ipv4.Address))) {
589 //no udhcpc's default.script exist, directly set ip and dns
590 update_ip_address_by_qmi(ifname, &profile->ipv4, NULL);
591 }
592 #endif
593 }
594
595 #ifdef QL_OPENWER_NETWORK_SETUP
596 ql_openwrt_setup_wan(ifname, &profile->ipv4);
597 #endif
598
599 set_ipv6:
600 if (profile->ipv6.Address[0] && profile->ipv6.PrefixLengthIPAddr) {
601 #if 1
602 //module do not support DHCPv6, only support 'Router Solicit'
603 //and it seem if enable /proc/sys/net/ipv6/conf/all/forwarding, Kernel do not send RS
604 const char *forward_file = "/proc/sys/net/ipv6/conf/all/forwarding";
605 int forward_fd = open(forward_file, O_RDONLY);
606 if (forward_fd > 0) {
607 char forward_state[2];
608 if (read(forward_fd, forward_state, 2) == -1) {};
609 if (forward_state[0] == '1') {
610 //dbg_time("%s enabled, kernel maybe donot send 'Router Solicit'", forward_file);
611 }
612 close(forward_fd);
613 }
614
615 update_ip_address_by_qmi(ifname, NULL, &profile->ipv6);
616
617 if (profile->ipv6.DnsPrimary[0] || profile->ipv6.DnsSecondary[0]) {
618 char dns1str[64], dns2str[64];
619
620 if (profile->ipv6.DnsPrimary[0]) {
621 strcpy(dns1str, ipv6Str(profile->ipv6.DnsPrimary));
622 }
623
624 if (profile->ipv6.DnsSecondary[0]) {
625 strcpy(dns2str, ipv6Str(profile->ipv6.DnsSecondary));
626 }
627
628 update_resolv_conf(6, ifname, profile->ipv6.DnsPrimary[0] ? dns1str : NULL,
629 profile->ipv6.DnsSecondary[0] != '\0' ? dns2str : NULL);
630 }
631
632 #ifdef QL_OPENWER_NETWORK_SETUP
633 ql_openwrt_setup_wan6(ifname, &profile->ipv6);
634 #endif
635 #else
636 #ifdef USE_DHCLIENT
637 snprintf(udhcpc_cmd, sizeof(udhcpc_cmd), "dhclient -6 -d --no-pid %s", ifname);
638 dhclient_alive++;
639 #else
640 /*
641 DHCPv6: Dibbler - a portable DHCPv6
642 1. download from http://klub.com.pl/dhcpv6/
643 2. cross-compile
644 2.1 ./configure --host=arm-linux-gnueabihf
645 2.2 copy dibbler-client to your board
646 3. mkdir -p /var/log/dibbler/ /var/lib/ on your board
647 4. create /etc/dibbler/client.conf on your board, the content is
648 log-mode short
649 log-level 7
650 iface wwan0 {
651 ia
652 option dns-server
653 }
654 5. run "dibbler-client start" to get ipV6 address
655 6. run "route -A inet6 add default dev wwan0" to add default route
656 */
657 snprintf(shell_cmd, sizeof(shell_cmd), "route -A inet6 add default %s", ifname);
658 ql_system(shell_cmd);
659 snprintf(udhcpc_cmd, sizeof(udhcpc_cmd), "dibbler-client run");
660 dibbler_client_alive++;
661 #endif
662
663 pthread_create(&udhcpc_thread_id, &udhcpc_thread_attr, udhcpc_thread_function, (void*)strdup(udhcpc_cmd));
664 #endif
665 }
666 }
667
udhcpc_stop(PROFILE_T * profile)668 void udhcpc_stop(PROFILE_T *profile) {
669 char *ifname = profile->usbnet_adapter;
670 char shell_cmd[128];
671
672 ql_set_driver_link_state(profile, 0);
673
674 if (profile->qmapnet_adapter[0]) {
675 ifname = profile->qmapnet_adapter;
676 }
677
678 #ifdef USE_DHCLIENT
679 if (dhclient_alive) {
680 system("killall dhclient");
681 dhclient_alive = 0;
682 }
683 #endif
684 if (dibbler_client_alive) {
685 if (system("killall dibbler-client")) {};
686 dibbler_client_alive = 0;
687 }
688
689 //it seems when call netif_carrier_on(), and netcard 's IP is "0.0.0.0", will cause netif_queue_stopped()
690 snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s 0.0.0.0", ifname);
691 ql_system(shell_cmd);
692 snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s down", ifname);
693 ql_system(shell_cmd);
694
695 #ifdef QL_OPENWER_NETWORK_SETUP
696 ql_openwrt_setup_wan(ifname, NULL);
697 ql_openwrt_setup_wan6(ifname, NULL);
698 #endif
699 }
700