Home | History | Annotate | Download | only in libnetutils
      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 HOSTNAME_PROP_NAME[] = "net.hostname";
     30 static const char DHCP_PROP_NAME_PREFIX[]  = "dhcp";
     31 static const char DAEMON_NAME_RENEW[]  = "iprenew";
     32 static const int  NAP_TIME = 1;   /* wait for 1 second at a time */
     33                                   /* when polling for property values */
     34 static char errmsg[100];
     35 
     36 /*
     37  * Wait for a system property to be assigned a specified value.
     38  * If desired_value is NULL, then just wait for the property to
     39  * be created with any value. maxwait is the maximum amount of
     40  * time in seconds to wait before giving up.
     41  */
     42 static int wait_for_property(const char *name, const char *desired_value, int maxwait)
     43 {
     44     char value[PROPERTY_VALUE_MAX] = {'\0'};
     45     int maxnaps = maxwait / NAP_TIME;
     46 
     47     if (maxnaps < 1) {
     48         maxnaps = 1;
     49     }
     50 
     51     while (maxnaps-- > 0) {
     52         usleep(1000000);
     53         if (property_get(name, value, NULL)) {
     54             if (desired_value == NULL ||
     55                     strcmp(value, desired_value) == 0) {
     56                 return 0;
     57             }
     58         }
     59     }
     60     return -1; /* failure */
     61 }
     62 
     63 static void fill_ip_info(const char *interface,
     64                      in_addr_t *ipaddr,
     65                      in_addr_t *gateway,
     66                      in_addr_t *mask,
     67                      in_addr_t *dns1,
     68                      in_addr_t *dns2,
     69                      in_addr_t *server,
     70                      uint32_t  *lease)
     71 {
     72     char prop_name[PROPERTY_KEY_MAX];
     73     char prop_value[PROPERTY_VALUE_MAX];
     74     struct in_addr addr;
     75     in_addr_t iaddr;
     76 
     77     snprintf(prop_name, sizeof(prop_name), "%s.%s.ipaddress", DHCP_PROP_NAME_PREFIX, interface);
     78     if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
     79         *ipaddr = addr.s_addr;
     80     } else {
     81         *ipaddr = 0;
     82     }
     83     snprintf(prop_name, sizeof(prop_name), "%s.%s.gateway", DHCP_PROP_NAME_PREFIX, interface);
     84     if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
     85         *gateway = addr.s_addr;
     86     } else {
     87         *gateway = 0;
     88     }
     89     snprintf(prop_name, sizeof(prop_name), "%s.%s.mask", DHCP_PROP_NAME_PREFIX, interface);
     90     if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
     91         *mask = addr.s_addr;
     92     } else {
     93         *mask = 0;
     94     }
     95     snprintf(prop_name, sizeof(prop_name), "%s.%s.dns1", DHCP_PROP_NAME_PREFIX, interface);
     96     if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
     97         *dns1 = addr.s_addr;
     98     } else {
     99         *dns1 = 0;
    100     }
    101     snprintf(prop_name, sizeof(prop_name), "%s.%s.dns2", DHCP_PROP_NAME_PREFIX, interface);
    102     if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
    103         *dns2 = addr.s_addr;
    104     } else {
    105         *dns2 = 0;
    106     }
    107     snprintf(prop_name, sizeof(prop_name), "%s.%s.server", DHCP_PROP_NAME_PREFIX, interface);
    108     if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
    109         *server = addr.s_addr;
    110     } else {
    111         *server = 0;
    112     }
    113     snprintf(prop_name, sizeof(prop_name), "%s.%s.leasetime", DHCP_PROP_NAME_PREFIX, interface);
    114     if (property_get(prop_name, prop_value, NULL)) {
    115         *lease = atol(prop_value);
    116     }
    117 }
    118 
    119 /*
    120  * Start the dhcp client daemon, and wait for it to finish
    121  * configuring the interface.
    122  */
    123 int dhcp_do_request(const char *interface,
    124                     in_addr_t *ipaddr,
    125                     in_addr_t *gateway,
    126                     in_addr_t *mask,
    127                     in_addr_t *dns1,
    128                     in_addr_t *dns2,
    129                     in_addr_t *server,
    130                     uint32_t  *lease)
    131 {
    132     char result_prop_name[PROPERTY_KEY_MAX];
    133     char daemon_prop_name[PROPERTY_KEY_MAX];
    134     char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
    135     char daemon_cmd[PROPERTY_VALUE_MAX * 2];
    136     const char *ctrl_prop = "ctl.start";
    137     const char *desired_status = "running";
    138 
    139     snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
    140             DHCP_PROP_NAME_PREFIX,
    141             interface);
    142 
    143     snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",
    144             DAEMON_PROP_NAME,
    145             interface);
    146 
    147     /* Erase any previous setting of the dhcp result property */
    148     property_set(result_prop_name, "");
    149 
    150     /* Start the daemon and wait until it's ready */
    151     if (property_get(HOSTNAME_PROP_NAME, prop_value, NULL) && (prop_value[0] != '\0'))
    152         snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-h %s %s", DAEMON_NAME, interface,
    153                  prop_value, interface);
    154     else
    155         snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:%s", DAEMON_NAME, interface, interface);
    156     memset(prop_value, '\0', PROPERTY_VALUE_MAX);
    157     property_set(ctrl_prop, daemon_cmd);
    158     if (wait_for_property(daemon_prop_name, desired_status, 10) < 0) {
    159         snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for dhcpcd to start");
    160         return -1;
    161     }
    162 
    163     /* Wait for the daemon to return a result */
    164     if (wait_for_property(result_prop_name, NULL, 30) < 0) {
    165         snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for DHCP to finish");
    166         return -1;
    167     }
    168 
    169     if (!property_get(result_prop_name, prop_value, NULL)) {
    170         /* shouldn't ever happen, given the success of wait_for_property() */
    171         snprintf(errmsg, sizeof(errmsg), "%s", "DHCP result property was not set");
    172         return -1;
    173     }
    174     if (strcmp(prop_value, "ok") == 0) {
    175         fill_ip_info(interface, ipaddr, gateway, mask, dns1, dns2, server, lease);
    176         return 0;
    177     } else {
    178         snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value);
    179         return -1;
    180     }
    181 }
    182 
    183 /**
    184  * Stop the DHCP client daemon.
    185  */
    186 int dhcp_stop(const char *interface)
    187 {
    188     char result_prop_name[PROPERTY_KEY_MAX];
    189     char daemon_prop_name[PROPERTY_KEY_MAX];
    190     char daemon_cmd[PROPERTY_VALUE_MAX * 2];
    191     const char *ctrl_prop = "ctl.stop";
    192     const char *desired_status = "stopped";
    193 
    194     snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
    195             DHCP_PROP_NAME_PREFIX,
    196             interface);
    197 
    198     snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",
    199             DAEMON_PROP_NAME,
    200             interface);
    201 
    202     snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME, interface);
    203 
    204     /* Stop the daemon and wait until it's reported to be stopped */
    205     property_set(ctrl_prop, daemon_cmd);
    206     if (wait_for_property(daemon_prop_name, desired_status, 5) < 0) {
    207         return -1;
    208     }
    209     property_set(result_prop_name, "failed");
    210     return 0;
    211 }
    212 
    213 /**
    214  * Release the current DHCP client lease.
    215  */
    216 int dhcp_release_lease(const char *interface)
    217 {
    218     char daemon_prop_name[PROPERTY_KEY_MAX];
    219     char daemon_cmd[PROPERTY_VALUE_MAX * 2];
    220     const char *ctrl_prop = "ctl.stop";
    221     const char *desired_status = "stopped";
    222 
    223     snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",
    224             DAEMON_PROP_NAME,
    225             interface);
    226 
    227     snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME, interface);
    228 
    229     /* Stop the daemon and wait until it's reported to be stopped */
    230     property_set(ctrl_prop, daemon_cmd);
    231     if (wait_for_property(daemon_prop_name, desired_status, 5) < 0) {
    232         return -1;
    233     }
    234     return 0;
    235 }
    236 
    237 char *dhcp_get_errmsg() {
    238     return errmsg;
    239 }
    240 
    241 /**
    242  * Run WiMAX dhcp renew service.
    243  * "wimax_renew" service shoud be included in init.rc.
    244  */
    245 int dhcp_do_request_renew(const char *interface,
    246                     in_addr_t *ipaddr,
    247                     in_addr_t *gateway,
    248                     in_addr_t *mask,
    249                     in_addr_t *dns1,
    250                     in_addr_t *dns2,
    251                     in_addr_t *server,
    252                     uint32_t  *lease)
    253 {
    254     char result_prop_name[PROPERTY_KEY_MAX];
    255     char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
    256     char daemon_cmd[PROPERTY_VALUE_MAX * 2];
    257     const char *ctrl_prop = "ctl.start";
    258 
    259     snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
    260             DHCP_PROP_NAME_PREFIX,
    261             interface);
    262 
    263     /* Erase any previous setting of the dhcp result property */
    264     property_set(result_prop_name, "");
    265 
    266     /* Start the renew daemon and wait until it's ready */
    267     snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:%s", DAEMON_NAME_RENEW, interface, interface);
    268     memset(prop_value, '\0', PROPERTY_VALUE_MAX);
    269     property_set(ctrl_prop, daemon_cmd);
    270 
    271     /* Wait for the daemon to return a result */
    272     if (wait_for_property(result_prop_name, NULL, 30) < 0) {
    273         snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for DHCP Renew to finish");
    274         return -1;
    275     }
    276 
    277     if (!property_get(result_prop_name, prop_value, NULL)) {
    278         /* shouldn't ever happen, given the success of wait_for_property() */
    279         snprintf(errmsg, sizeof(errmsg), "%s", "DHCP Renew result property was not set");
    280         return -1;
    281     }
    282     if (strcmp(prop_value, "ok") == 0) {
    283         fill_ip_info(interface, ipaddr, gateway, mask, dns1, dns2, server, lease);
    284         return 0;
    285     } else {
    286         snprintf(errmsg, sizeof(errmsg), "DHCP Renew result was %s", prop_value);
    287         return -1;
    288     }
    289 }