• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 /* Utilities for managing the dhcpcd DHCP client daemon */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <arpa/inet.h>
23 #include <netinet/in.h>
24 
25 #include <cutils/properties.h>
26 
27 static const char DAEMON_NAME[]       = "dhcpcd";
28 static const char DAEMON_PROP_NAME[]  = "init.svc.dhcpcd";
29 static const char DHCP_PROP_NAME_PREFIX[]  = "dhcp";
30 static const int  NAP_TIME = 1;   /* wait for 1 second at a time */
31                                   /* when polling for property values */
32 static char errmsg[100];
33 
34 /*
35  * Wait for a system property to be assigned a specified value.
36  * If desired_value is NULL, then just wait for the property to
37  * be created with any value. maxwait is the maximum amount of
38  * time in seconds to wait before giving up.
39  */
wait_for_property(const char * name,const char * desired_value,int maxwait)40 static int wait_for_property(const char *name, const char *desired_value, int maxwait)
41 {
42     char value[PROPERTY_VALUE_MAX] = {'\0'};
43     int maxnaps = maxwait / NAP_TIME;
44 
45     if (maxnaps < 1) {
46         maxnaps = 1;
47     }
48 
49     while (maxnaps-- > 0) {
50         usleep(1000000);
51         if (property_get(name, value, NULL)) {
52             if (desired_value == NULL ||
53                     strcmp(value, desired_value) == 0) {
54                 return 0;
55             }
56         }
57     }
58     return -1; /* failure */
59 }
60 
fill_ip_info(const char * interface,in_addr_t * ipaddr,in_addr_t * gateway,in_addr_t * mask,in_addr_t * dns1,in_addr_t * dns2,in_addr_t * server,uint32_t * lease)61 static void fill_ip_info(const char *interface,
62                      in_addr_t *ipaddr,
63                      in_addr_t *gateway,
64                      in_addr_t *mask,
65                      in_addr_t *dns1,
66                      in_addr_t *dns2,
67                      in_addr_t *server,
68                      uint32_t  *lease)
69 {
70     char prop_name[PROPERTY_KEY_MAX];
71     char prop_value[PROPERTY_VALUE_MAX];
72     struct in_addr addr;
73     in_addr_t iaddr;
74 
75     snprintf(prop_name, sizeof(prop_name), "%s.%s.ipaddress", DHCP_PROP_NAME_PREFIX, interface);
76     if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
77         *ipaddr = addr.s_addr;
78     } else {
79         *ipaddr = 0;
80     }
81     snprintf(prop_name, sizeof(prop_name), "%s.%s.gateway", DHCP_PROP_NAME_PREFIX, interface);
82     if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
83         *gateway = addr.s_addr;
84     } else {
85         *gateway = 0;
86     }
87     snprintf(prop_name, sizeof(prop_name), "%s.%s.mask", DHCP_PROP_NAME_PREFIX, interface);
88     if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
89         *mask = addr.s_addr;
90     } else {
91         *mask = 0;
92     }
93     snprintf(prop_name, sizeof(prop_name), "%s.%s.dns1", DHCP_PROP_NAME_PREFIX, interface);
94     if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
95         *dns1 = addr.s_addr;
96     } else {
97         *dns1 = 0;
98     }
99     snprintf(prop_name, sizeof(prop_name), "%s.%s.dns2", DHCP_PROP_NAME_PREFIX, interface);
100     if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
101         *dns2 = addr.s_addr;
102     } else {
103         *dns2 = 0;
104     }
105     snprintf(prop_name, sizeof(prop_name), "%s.%s.server", DHCP_PROP_NAME_PREFIX, interface);
106     if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
107         *server = addr.s_addr;
108     } else {
109         *server = 0;
110     }
111     snprintf(prop_name, sizeof(prop_name), "%s.%s.leasetime", DHCP_PROP_NAME_PREFIX, interface);
112     if (property_get(prop_name, prop_value, NULL)) {
113         *lease = atol(prop_value);
114     }
115 }
116 
117 /*
118  * Start the dhcp client daemon, and wait for it to finish
119  * configuring the interface.
120  */
dhcp_do_request(const char * interface,in_addr_t * ipaddr,in_addr_t * gateway,in_addr_t * mask,in_addr_t * dns1,in_addr_t * dns2,in_addr_t * server,uint32_t * lease)121 int dhcp_do_request(const char *interface,
122                     in_addr_t *ipaddr,
123                     in_addr_t *gateway,
124                     in_addr_t *mask,
125                     in_addr_t *dns1,
126                     in_addr_t *dns2,
127                     in_addr_t *server,
128                     uint32_t  *lease)
129 {
130     char result_prop_name[PROPERTY_KEY_MAX];
131     char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
132     const char *ctrl_prop = "ctl.start";
133     const char *desired_status = "running";
134 
135     snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
136             DHCP_PROP_NAME_PREFIX,
137             interface);
138     /* Erase any previous setting of the dhcp result property */
139     property_set(result_prop_name, "");
140 
141     /* Start the daemon and wait until it's ready */
142     property_set(ctrl_prop, DAEMON_NAME);
143     if (wait_for_property(DAEMON_PROP_NAME, desired_status, 10) < 0) {
144         snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for dhcpcd to start");
145         return -1;
146     }
147 
148     /* Wait for the daemon to return a result */
149     if (wait_for_property(result_prop_name, NULL, 30) < 0) {
150         snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for DHCP to finish");
151         return -1;
152     }
153 
154     if (!property_get(result_prop_name, prop_value, NULL)) {
155         /* shouldn't ever happen, given the success of wait_for_property() */
156         snprintf(errmsg, sizeof(errmsg), "%s", "DHCP result property was not set");
157         return -1;
158     }
159     if (strcmp(prop_value, "ok") == 0) {
160         fill_ip_info(interface, ipaddr, gateway, mask, dns1, dns2, server, lease);
161         return 0;
162     } else {
163         snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value);
164         return -1;
165     }
166 }
167 
168 /**
169  * Stop the DHCP client daemon.
170  */
dhcp_stop(const char * interface)171 int dhcp_stop(const char *interface)
172 {
173     char result_prop_name[PROPERTY_KEY_MAX];
174     const char *ctrl_prop = "ctl.stop";
175     const char *desired_status = "stopped";
176 
177     snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
178             DHCP_PROP_NAME_PREFIX,
179             interface);
180     /* Stop the daemon and wait until it's reported to be stopped */
181     property_set(ctrl_prop, DAEMON_NAME);
182     if (wait_for_property(DAEMON_PROP_NAME, desired_status, 5) < 0) {
183         return -1;
184     }
185     property_set(result_prop_name, "failed");
186     return 0;
187 }
188 
189 /**
190  * Release the current DHCP client lease.
191  */
dhcp_release_lease(const char * interface)192 int dhcp_release_lease(const char *interface)
193 {
194     const char *ctrl_prop = "ctl.stop";
195     const char *desired_status = "stopped";
196 
197     /* Stop the daemon and wait until it's reported to be stopped */
198     property_set(ctrl_prop, DAEMON_NAME);
199     if (wait_for_property(DAEMON_PROP_NAME, desired_status, 5) < 0) {
200         return -1;
201     }
202     return 0;
203 }
204 
dhcp_get_errmsg()205 char *dhcp_get_errmsg() {
206     return errmsg;
207 }
208