You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

675 lines
22 KiB

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