PageRenderTime 97ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/libnetutils/dhcp_utils.c

https://gitlab.com/infraredbg/android_system_core-mt6589
C | 381 lines | 252 code | 53 blank | 76 comment | 45 complexity | 26e50e16797fa70e3d4fdd2a935243ad MD5 | raw file
  1. /*
  2. * Copyright 2008, The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /* Utilities for managing the dhcpcd DHCP client daemon */
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <unistd.h>
  21. #include <arpa/inet.h>
  22. #include <netinet/in.h>
  23. #include <cutils/properties.h>
  24. static const char DAEMON_NAME[] = "dhcpcd";
  25. static const char DAEMON_PROP_NAME[] = "init.svc.dhcpcd";
  26. static const char HOSTNAME_PROP_NAME[] = "net.hostname";
  27. static const char DHCP_PROP_NAME_PREFIX[] = "dhcp";
  28. static const char DHCP_CONFIG_PATH[] = "/system/etc/dhcpcd/dhcpcd.conf";
  29. static const int NAP_TIME = 200; /* wait for 200ms at a time */
  30. /* when polling for property values */
  31. static const char DAEMON_NAME_RENEW[] = "iprenew";
  32. static char errmsg[100];
  33. /* interface length for dhcpcd daemon start (dhcpcd_<interface> as defined in init.rc file)
  34. * or for filling up system properties dhcpcd.<interface>.ipaddress, dhcpcd.<interface>.dns1
  35. * and other properties on a successful bind
  36. */
  37. #define MAX_INTERFACE_LENGTH 25
  38. /*
  39. * P2p interface names increase sequentially p2p-p2p0-1, p2p-p2p0-2.. after
  40. * group formation. This does not work well with system properties which can quickly
  41. * exhaust or for specifiying a dhcp start target in init which requires
  42. * interface to be pre-defined in init.rc file.
  43. *
  44. * This function returns a common string p2p for all p2p interfaces.
  45. */
  46. void get_p2p_interface_replacement(const char *interface, char *p2p_interface) {
  47. /* Use p2p for any interface starting with p2p. */
  48. if (strncmp(interface, "p2p",3) == 0) {
  49. strncpy(p2p_interface, "p2p", MAX_INTERFACE_LENGTH);
  50. } else {
  51. strncpy(p2p_interface, interface, MAX_INTERFACE_LENGTH);
  52. }
  53. }
  54. /*
  55. * Wait for a system property to be assigned a specified value.
  56. * If desired_value is NULL, then just wait for the property to
  57. * be created with any value. maxwait is the maximum amount of
  58. * time in seconds to wait before giving up.
  59. */
  60. static int wait_for_property(const char *name, const char *desired_value, int maxwait)
  61. {
  62. char value[PROPERTY_VALUE_MAX] = {'\0'};
  63. int maxnaps = (maxwait * 1000) / NAP_TIME;
  64. if (maxnaps < 1) {
  65. maxnaps = 1;
  66. }
  67. while (maxnaps-- > 0) {
  68. usleep(NAP_TIME * 1000);
  69. if (property_get(name, value, NULL)) {
  70. if (desired_value == NULL ||
  71. strcmp(value, desired_value) == 0) {
  72. return 0;
  73. }
  74. }
  75. }
  76. return -1; /* failure */
  77. }
  78. static int fill_ip_info(const char *interface,
  79. char *ipaddr,
  80. char *gateway,
  81. uint32_t *prefixLength,
  82. char *dns[],
  83. char *server,
  84. uint32_t *lease,
  85. char *vendorInfo,
  86. char *domain,
  87. char *mtu)
  88. {
  89. char prop_name[PROPERTY_KEY_MAX];
  90. char prop_value[PROPERTY_VALUE_MAX];
  91. /* Interface name after converting p2p0-p2p0-X to p2p to reuse system properties */
  92. char p2p_interface[MAX_INTERFACE_LENGTH];
  93. int x;
  94. get_p2p_interface_replacement(interface, p2p_interface);
  95. snprintf(prop_name, sizeof(prop_name), "%s.%s.ipaddress", DHCP_PROP_NAME_PREFIX, p2p_interface);
  96. property_get(prop_name, ipaddr, NULL);
  97. snprintf(prop_name, sizeof(prop_name), "%s.%s.gateway", DHCP_PROP_NAME_PREFIX, p2p_interface);
  98. property_get(prop_name, gateway, NULL);
  99. snprintf(prop_name, sizeof(prop_name), "%s.%s.server", DHCP_PROP_NAME_PREFIX, p2p_interface);
  100. property_get(prop_name, server, NULL);
  101. //TODO: Handle IPv6 when we change system property usage
  102. if (gateway[0] == '\0' || strncmp(gateway, "0.0.0.0", 7) == 0) {
  103. //DHCP server is our best bet as gateway
  104. strncpy(gateway, server, PROPERTY_VALUE_MAX);
  105. }
  106. snprintf(prop_name, sizeof(prop_name), "%s.%s.mask", DHCP_PROP_NAME_PREFIX, p2p_interface);
  107. if (property_get(prop_name, prop_value, NULL)) {
  108. int p;
  109. // this conversion is v4 only, but this dhcp client is v4 only anyway
  110. in_addr_t mask = ntohl(inet_addr(prop_value));
  111. // Check netmask is a valid IP address. ntohl gives NONE response (all 1's) for
  112. // non 255.255.255.255 inputs. if we get that value check if it is legit..
  113. if (mask == INADDR_NONE && strcmp(prop_value, "255.255.255.255") != 0) {
  114. snprintf(errmsg, sizeof(errmsg), "DHCP gave invalid net mask %s", prop_value);
  115. return -1;
  116. }
  117. for (p = 0; p < 32; p++) {
  118. if (mask == 0) break;
  119. // check for non-contiguous netmask, e.g., 255.254.255.0
  120. if ((mask & 0x80000000) == 0) {
  121. snprintf(errmsg, sizeof(errmsg), "DHCP gave invalid net mask %s", prop_value);
  122. return -1;
  123. }
  124. mask = mask << 1;
  125. }
  126. *prefixLength = p;
  127. }
  128. for (x=0; dns[x] != NULL; x++) {
  129. snprintf(prop_name, sizeof(prop_name), "%s.%s.dns%d", DHCP_PROP_NAME_PREFIX, p2p_interface, x+1);
  130. property_get(prop_name, dns[x], NULL);
  131. }
  132. snprintf(prop_name, sizeof(prop_name), "%s.%s.leasetime", DHCP_PROP_NAME_PREFIX, p2p_interface);
  133. if (property_get(prop_name, prop_value, NULL)) {
  134. *lease = atol(prop_value);
  135. }
  136. snprintf(prop_name, sizeof(prop_name), "%s.%s.vendorInfo", DHCP_PROP_NAME_PREFIX,
  137. p2p_interface);
  138. property_get(prop_name, vendorInfo, NULL);
  139. snprintf(prop_name, sizeof(prop_name), "%s.%s.domain", DHCP_PROP_NAME_PREFIX,
  140. p2p_interface);
  141. property_get(prop_name, domain, NULL);
  142. snprintf(prop_name, sizeof(prop_name), "%s.%s.mtu", DHCP_PROP_NAME_PREFIX,
  143. p2p_interface);
  144. property_get(prop_name, mtu, NULL);
  145. return 0;
  146. }
  147. static const char *ipaddr_to_string(in_addr_t addr)
  148. {
  149. struct in_addr in_addr;
  150. in_addr.s_addr = addr;
  151. return inet_ntoa(in_addr);
  152. }
  153. /*
  154. * Start the dhcp client daemon, and wait for it to finish
  155. * configuring the interface.
  156. *
  157. * The device init.rc file needs a corresponding entry for this work.
  158. *
  159. * Example:
  160. * service dhcpcd_<interface> /system/bin/dhcpcd -ABKL -f dhcpcd.conf
  161. */
  162. int dhcp_do_request(const char *interface,
  163. char *ipaddr,
  164. char *gateway,
  165. uint32_t *prefixLength,
  166. char *dns[],
  167. char *server,
  168. uint32_t *lease,
  169. char *vendorInfo,
  170. char *domain,
  171. char *mtu)
  172. {
  173. char result_prop_name[PROPERTY_KEY_MAX];
  174. char daemon_prop_name[PROPERTY_KEY_MAX];
  175. char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
  176. char daemon_cmd[PROPERTY_VALUE_MAX * 2 + sizeof(DHCP_CONFIG_PATH)];
  177. const char *ctrl_prop = "ctl.start";
  178. const char *desired_status = "running";
  179. /* Interface name after converting p2p0-p2p0-X to p2p to reuse system properties */
  180. char p2p_interface[MAX_INTERFACE_LENGTH];
  181. get_p2p_interface_replacement(interface, p2p_interface);
  182. snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
  183. DHCP_PROP_NAME_PREFIX,
  184. p2p_interface);
  185. snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",
  186. DAEMON_PROP_NAME,
  187. p2p_interface);
  188. /* Erase any previous setting of the dhcp result property */
  189. property_set(result_prop_name, "");
  190. /* Start the daemon and wait until it's ready */
  191. if (property_get(HOSTNAME_PROP_NAME, prop_value, NULL) && (prop_value[0] != '\0'))
  192. snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-f %s -h %s %s", DAEMON_NAME,
  193. p2p_interface, DHCP_CONFIG_PATH, prop_value, interface);
  194. else
  195. snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-f %s %s", DAEMON_NAME,
  196. p2p_interface, DHCP_CONFIG_PATH, interface);
  197. memset(prop_value, '\0', PROPERTY_VALUE_MAX);
  198. property_set(ctrl_prop, daemon_cmd);
  199. if (wait_for_property(daemon_prop_name, desired_status, 10) < 0) {
  200. snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for dhcpcd to start");
  201. return -1;
  202. }
  203. /* Wait for the daemon to return a result */
  204. if (wait_for_property(result_prop_name, NULL, 30) < 0) {
  205. snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for DHCP to finish");
  206. return -1;
  207. }
  208. if (!property_get(result_prop_name, prop_value, NULL)) {
  209. /* shouldn't ever happen, given the success of wait_for_property() */
  210. snprintf(errmsg, sizeof(errmsg), "%s", "DHCP result property was not set");
  211. return -1;
  212. }
  213. if (strcmp(prop_value, "ok") == 0) {
  214. char dns_prop_name[PROPERTY_KEY_MAX];
  215. if (fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
  216. server, lease, vendorInfo, domain, mtu) == -1) {
  217. return -1;
  218. }
  219. return 0;
  220. } else {
  221. snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value);
  222. return -1;
  223. }
  224. }
  225. /**
  226. * Stop the DHCP client daemon.
  227. */
  228. int dhcp_stop(const char *interface)
  229. {
  230. char result_prop_name[PROPERTY_KEY_MAX];
  231. char daemon_prop_name[PROPERTY_KEY_MAX];
  232. char daemon_cmd[PROPERTY_VALUE_MAX * 2];
  233. const char *ctrl_prop = "ctl.stop";
  234. const char *desired_status = "stopped";
  235. char p2p_interface[MAX_INTERFACE_LENGTH];
  236. get_p2p_interface_replacement(interface, p2p_interface);
  237. snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
  238. DHCP_PROP_NAME_PREFIX,
  239. p2p_interface);
  240. snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",
  241. DAEMON_PROP_NAME,
  242. p2p_interface);
  243. snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME, p2p_interface);
  244. /* Stop the daemon and wait until it's reported to be stopped */
  245. property_set(ctrl_prop, daemon_cmd);
  246. if (wait_for_property(daemon_prop_name, desired_status, 5) < 0) {
  247. return -1;
  248. }
  249. property_set(result_prop_name, "failed");
  250. return 0;
  251. }
  252. /**
  253. * Release the current DHCP client lease.
  254. */
  255. int dhcp_release_lease(const char *interface)
  256. {
  257. char daemon_prop_name[PROPERTY_KEY_MAX];
  258. char daemon_cmd[PROPERTY_VALUE_MAX * 2];
  259. const char *ctrl_prop = "ctl.stop";
  260. const char *desired_status = "stopped";
  261. char p2p_interface[MAX_INTERFACE_LENGTH];
  262. get_p2p_interface_replacement(interface, p2p_interface);
  263. snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",
  264. DAEMON_PROP_NAME,
  265. p2p_interface);
  266. snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME, p2p_interface);
  267. /* Stop the daemon and wait until it's reported to be stopped */
  268. property_set(ctrl_prop, daemon_cmd);
  269. if (wait_for_property(daemon_prop_name, desired_status, 5) < 0) {
  270. return -1;
  271. }
  272. return 0;
  273. }
  274. char *dhcp_get_errmsg() {
  275. return errmsg;
  276. }
  277. /**
  278. * The device init.rc file needs a corresponding entry.
  279. *
  280. * Example:
  281. * service iprenew_<interface> /system/bin/dhcpcd -n
  282. *
  283. */
  284. int dhcp_do_request_renew(const char *interface,
  285. char *ipaddr,
  286. char *gateway,
  287. uint32_t *prefixLength,
  288. char *dns[],
  289. char *server,
  290. uint32_t *lease,
  291. char *vendorInfo,
  292. char *domain,
  293. char *mtu)
  294. {
  295. char result_prop_name[PROPERTY_KEY_MAX];
  296. char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
  297. char daemon_cmd[PROPERTY_VALUE_MAX * 2];
  298. const char *ctrl_prop = "ctl.start";
  299. char p2p_interface[MAX_INTERFACE_LENGTH];
  300. get_p2p_interface_replacement(interface, p2p_interface);
  301. snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
  302. DHCP_PROP_NAME_PREFIX,
  303. p2p_interface);
  304. /* Erase any previous setting of the dhcp result property */
  305. property_set(result_prop_name, "");
  306. /* Start the renew daemon and wait until it's ready */
  307. snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:%s", DAEMON_NAME_RENEW,
  308. p2p_interface, interface);
  309. memset(prop_value, '\0', PROPERTY_VALUE_MAX);
  310. property_set(ctrl_prop, daemon_cmd);
  311. /* Wait for the daemon to return a result */
  312. if (wait_for_property(result_prop_name, NULL, 30) < 0) {
  313. snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for DHCP Renew to finish");
  314. return -1;
  315. }
  316. if (!property_get(result_prop_name, prop_value, NULL)) {
  317. /* shouldn't ever happen, given the success of wait_for_property() */
  318. snprintf(errmsg, sizeof(errmsg), "%s", "DHCP Renew result property was not set");
  319. return -1;
  320. }
  321. if (strcmp(prop_value, "ok") == 0) {
  322. return fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
  323. server, lease, vendorInfo, domain, mtu);
  324. } else {
  325. snprintf(errmsg, sizeof(errmsg), "DHCP Renew result was %s", prop_value);
  326. return -1;
  327. }
  328. }