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