xref: /OK3568_Linux_fs/app/forlinx/quectelCM/udhcpc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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