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