dhcpclient.c revision 8d66c49258ac4f59bd67c23c9c914cca81f85b01
1dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/*
2dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Copyright 2008, The Android Open Source Project
3dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
4dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * you may not use this file except in compliance with the License.
6dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * You may obtain a copy of the License at
7dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
8dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
9dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
10dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * See the License for the specific language governing permissions and
14dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * limitations under the License.
15dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
16dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
17dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdio.h>
18dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdarg.h>
19dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdlib.h>
20dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <unistd.h>
21dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <errno.h>
22dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <string.h>
23dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
24dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <time.h>
25dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/time.h>
26dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <poll.h>
27dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
28dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/socket.h>
29dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/select.h>
30dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/types.h>
31dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <netinet/in.h>
32dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
33dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <cutils/properties.h>
34dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define LOG_TAG "DHCP"
35dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <cutils/log.h>
36dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
37dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <dirent.h>
38dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
398c85a00db6da092ec3766facd49132fa4fc319a1Szymon Jakubczak#include <netutils/ifc.h>
40dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include "dhcpmsg.h"
41dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include "packet.h"
42dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
43dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define VERBOSE 2
44dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
45dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic int verbose = 1;
46dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic char errmsg[2048];
47dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
48dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projecttypedef unsigned long long msecs_t;
49dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE
50dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid dump_dhcp_msg();
51dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
52dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
53dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectmsecs_t get_msecs(void)
54dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
55dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct timespec ts;
56dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
57dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
58dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
59dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
60dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return (((msecs_t) ts.tv_sec) * ((msecs_t) 1000)) +
61dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            (((msecs_t) ts.tv_nsec) / ((msecs_t) 1000000));
62dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
63dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
64dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
65dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid printerr(char *fmt, ...)
66dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
67dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    va_list ap;
68dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
69dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    va_start(ap, fmt);
70dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    vsnprintf(errmsg, sizeof(errmsg), fmt, ap);
71dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    va_end(ap);
72dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
738d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("%s", errmsg);
74dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
75dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
76dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectconst char *dhcp_lasterror()
77dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
78dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return errmsg;
79dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
80dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
81dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint fatal(const char *reason)
82dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
83dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    printerr("%s: %s\n", reason, strerror(errno));
84dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return -1;
85dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project//    exit(1);
86dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
87dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
888c85a00db6da092ec3766facd49132fa4fc319a1Szymon Jakubczakconst char *ipaddr(in_addr_t addr)
89dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
908c85a00db6da092ec3766facd49132fa4fc319a1Szymon Jakubczak    struct in_addr in_addr;
918c85a00db6da092ec3766facd49132fa4fc319a1Szymon Jakubczak
928c85a00db6da092ec3766facd49132fa4fc319a1Szymon Jakubczak    in_addr.s_addr = addr;
938c85a00db6da092ec3766facd49132fa4fc319a1Szymon Jakubczak    return inet_ntoa(in_addr);
94dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
95dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
9609dd819d2794caf1a17cd03592c100755fb25577Robert Greenwaltextern int ipv4NetmaskToPrefixLength(in_addr_t mask);
9709dd819d2794caf1a17cd03592c100755fb25577Robert Greenwalt
98dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projecttypedef struct dhcp_info dhcp_info;
99dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
100dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstruct dhcp_info {
101dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t type;
102dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
103dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t ipaddr;
104dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t gateway;
10509dd819d2794caf1a17cd03592c100755fb25577Robert Greenwalt    uint32_t prefixLength;
106dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
107dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t dns1;
108dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t dns2;
109dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
110dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t serveraddr;
111dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t lease;
112dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project};
113dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
114dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectdhcp_info last_good_info;
115dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
11609dd819d2794caf1a17cd03592c100755fb25577Robert Greenwaltvoid get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *prefixLength,
117dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                   uint32_t *dns1, uint32_t *dns2, uint32_t *server,
118dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                   uint32_t *lease)
119dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
120dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    *ipaddr = last_good_info.ipaddr;
121dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    *gateway = last_good_info.gateway;
12209dd819d2794caf1a17cd03592c100755fb25577Robert Greenwalt    *prefixLength = last_good_info.prefixLength;
123dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    *dns1 = last_good_info.dns1;
124dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    *dns2 = last_good_info.dns2;
125dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    *server = last_good_info.serveraddr;
126dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    *lease = last_good_info.lease;
127dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
128dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1298c85a00db6da092ec3766facd49132fa4fc319a1Szymon Jakubczakstatic int dhcp_configure(const char *ifname, dhcp_info *info)
130dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
131dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    last_good_info = *info;
13209dd819d2794caf1a17cd03592c100755fb25577Robert Greenwalt    return ifc_configure(ifname, info->ipaddr, info->prefixLength, info->gateway,
1338c85a00db6da092ec3766facd49132fa4fc319a1Szymon Jakubczak                         info->dns1, info->dns2);
134dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
135dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
136dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic const char *dhcp_type_to_name(uint32_t type)
137dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
138dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    switch(type) {
139dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    case DHCPDISCOVER: return "discover";
140dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    case DHCPOFFER:    return "offer";
141dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    case DHCPREQUEST:  return "request";
142dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    case DHCPDECLINE:  return "decline";
143dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    case DHCPACK:      return "ack";
144dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    case DHCPNAK:      return "nak";
145dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    case DHCPRELEASE:  return "release";
146dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    case DHCPINFORM:   return "inform";
147dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    default:           return "???";
148dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
149dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
150dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
151dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid dump_dhcp_info(dhcp_info *info)
152dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
153dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char addr[20], gway[20], mask[20];
1548d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("--- dhcp %s (%d) ---",
155dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            dhcp_type_to_name(info->type), info->type);
156dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    strcpy(addr, ipaddr(info->ipaddr));
157dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    strcpy(gway, ipaddr(info->gateway));
1588d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("ip %s gw %s prefixLength %d", addr, gway, info->prefixLength);
1598d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    if (info->dns1) ALOGD("dns1: %s", ipaddr(info->dns1));
1608d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    if (info->dns2) ALOGD("dns2: %s", ipaddr(info->dns2));
1618d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("server %s, lease %d seconds",
162dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            ipaddr(info->serveraddr), info->lease);
163dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
164dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
165dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
166dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint decode_dhcp_msg(dhcp_msg *msg, int len, dhcp_info *info)
167dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
168dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint8_t *x;
169dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned int opt;
170dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int optlen;
171dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
172dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    memset(info, 0, sizeof(dhcp_info));
173dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (len < (DHCP_MSG_FIXED_SIZE + 4)) return -1;
174dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
175dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    len -= (DHCP_MSG_FIXED_SIZE + 4);
176dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
177dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (msg->options[0] != OPT_COOKIE1) return -1;
178dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (msg->options[1] != OPT_COOKIE2) return -1;
179dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (msg->options[2] != OPT_COOKIE3) return -1;
180dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (msg->options[3] != OPT_COOKIE4) return -1;
181dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
182dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    x = msg->options + 4;
183dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
184dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    while (len > 2) {
185dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        opt = *x++;
186dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (opt == OPT_PAD) {
187dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            len--;
188dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            continue;
189dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
190dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (opt == OPT_END) {
191dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
192dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
193dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        optlen = *x++;
194dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        len -= 2;
195dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (optlen > len) {
196dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
197dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
198dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        switch(opt) {
199dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case OPT_SUBNET_MASK:
2006d956cc0897f5a0225913e136c40053162be24aaJae Seo            if (optlen >= 4) info->prefixLength = ipv4NetmaskToPrefixLength(*((uint32_t*)x));
201dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
202dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case OPT_GATEWAY:
203dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (optlen >= 4) memcpy(&info->gateway, x, 4);
204dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
205dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case OPT_DNS:
206dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (optlen >= 4) memcpy(&info->dns1, x + 0, 4);
207dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (optlen >= 8) memcpy(&info->dns2, x + 4, 4);
208dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
209dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case OPT_LEASE_TIME:
210dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (optlen >= 4) {
211dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                memcpy(&info->lease, x, 4);
212dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                info->lease = ntohl(info->lease);
213dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
214dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
215dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case OPT_SERVER_ID:
216dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (optlen >= 4) memcpy(&info->serveraddr, x, 4);
217dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
218dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case OPT_MESSAGE_TYPE:
219dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            info->type = *x;
220dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
221dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        default:
222dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
223dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
224dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        x += optlen;
225dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        len -= optlen;
226dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
227dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
228dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    info->ipaddr = msg->yiaddr;
229dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
230dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 0;
231dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
232dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
233dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE
234dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
235dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void hex2str(char *buf, const unsigned char *array, int len)
236dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
237dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int i;
238dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char *cp = buf;
239dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
240dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    for (i = 0; i < len; i++) {
241dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        cp += sprintf(cp, " %02x ", array[i]);
242dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
243dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
244dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
245dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid dump_dhcp_msg(dhcp_msg *msg, int len)
246dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
247dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned char *x;
248dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned int n,c;
249dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int optsz;
250dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    const char *name;
251dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char buf[2048];
252dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
2538d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("===== DHCP message:");
254dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (len < DHCP_MSG_FIXED_SIZE) {
2558d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("Invalid length %d, should be %d", len, DHCP_MSG_FIXED_SIZE);
256dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return;
257dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
258dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
259dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    len -= DHCP_MSG_FIXED_SIZE;
260dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
261dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (msg->op == OP_BOOTREQUEST)
262dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        name = "BOOTREQUEST";
263dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    else if (msg->op == OP_BOOTREPLY)
264dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        name = "BOOTREPLY";
265dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    else
266dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        name = "????";
2678d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("op = %s (%d), htype = %d, hlen = %d, hops = %d",
268dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project           name, msg->op, msg->htype, msg->hlen, msg->hops);
2698d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("xid = 0x%08x secs = %d, flags = 0x%04x optlen = %d",
270dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project           ntohl(msg->xid), ntohs(msg->secs), ntohs(msg->flags), len);
2718d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("ciaddr = %s", ipaddr(msg->ciaddr));
2728d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("yiaddr = %s", ipaddr(msg->yiaddr));
2738d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("siaddr = %s", ipaddr(msg->siaddr));
2748d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("giaddr = %s", ipaddr(msg->giaddr));
275dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
276dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    c = msg->hlen > 16 ? 16 : msg->hlen;
277dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    hex2str(buf, msg->chaddr, c);
2788d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("chaddr = {%s}", buf);
279dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
280dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    for (n = 0; n < 64; n++) {
281dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if ((msg->sname[n] < ' ') || (msg->sname[n] > 127)) {
282dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (msg->sname[n] == 0) break;
283dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            msg->sname[n] = '.';
284dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
285dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
286dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msg->sname[63] = 0;
287dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
288dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    for (n = 0; n < 128; n++) {
289dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if ((msg->file[n] < ' ') || (msg->file[n] > 127)) {
290dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (msg->file[n] == 0) break;
291dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            msg->file[n] = '.';
292dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
293dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
294dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msg->file[127] = 0;
295dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
2968d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("sname = '%s'", msg->sname);
2978d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("file = '%s'", msg->file);
298dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
299dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (len < 4) return;
300dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    len -= 4;
301dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    x = msg->options + 4;
302dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
303dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    while (len > 2) {
304dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (*x == 0) {
305dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            x++;
306dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            len--;
307dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            continue;
308dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
309dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (*x == OPT_END) {
310dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
311dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
312dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        len -= 2;
313dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        optsz = x[1];
314dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (optsz > len) break;
315dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (x[0] == OPT_DOMAIN_NAME || x[0] == OPT_MESSAGE) {
316dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if ((unsigned int)optsz < sizeof(buf) - 1) {
317dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                n = optsz;
318dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            } else {
319dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                n = sizeof(buf) - 1;
320dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
321dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            memcpy(buf, &x[2], n);
322dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            buf[n] = '\0';
323dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        } else {
324dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            hex2str(buf, &x[2], optsz);
325dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
326dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (x[0] == OPT_MESSAGE_TYPE)
327dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            name = dhcp_type_to_name(x[2]);
328dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        else
329dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            name = NULL;
3308d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("op %d len %d {%s} %s", x[0], optsz, buf, name == NULL ? "" : name);
331dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        len -= optsz;
332dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        x = x + optsz + 2;
333dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
334dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
335dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
336dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
337dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
338dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic int send_message(int sock, int if_index, dhcp_msg  *msg, int size)
339dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
340dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE > 1
341dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dump_dhcp_msg(msg, size);
342dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
343dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return send_packet(sock, if_index, msg, size, INADDR_ANY, INADDR_BROADCAST,
344dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                       PORT_BOOTP_CLIENT, PORT_BOOTP_SERVER);
345dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
346dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
347dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic int is_valid_reply(dhcp_msg *msg, dhcp_msg *reply, int sz)
348dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
349dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (sz < DHCP_MSG_FIXED_SIZE) {
3508d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        if (verbose) ALOGD("netcfg: Wrong size %d != %d\n", sz, DHCP_MSG_FIXED_SIZE);
351dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
352dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
353dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (reply->op != OP_BOOTREPLY) {
3548d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        if (verbose) ALOGD("netcfg: Wrong Op %d != %d\n", reply->op, OP_BOOTREPLY);
355dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
356dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
357dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (reply->xid != msg->xid) {
3588d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        if (verbose) ALOGD("netcfg: Wrong Xid 0x%x != 0x%x\n", ntohl(reply->xid),
359dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                          ntohl(msg->xid));
360dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
361dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
362dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (reply->htype != msg->htype) {
3638d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        if (verbose) ALOGD("netcfg: Wrong Htype %d != %d\n", reply->htype, msg->htype);
364dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
365dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
366dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (reply->hlen != msg->hlen) {
3678d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        if (verbose) ALOGD("netcfg: Wrong Hlen %d != %d\n", reply->hlen, msg->hlen);
368dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
369dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
370dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (memcmp(msg->chaddr, reply->chaddr, msg->hlen)) {
3718d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        if (verbose) ALOGD("netcfg: Wrong chaddr %x != %x\n", *(reply->chaddr),*(msg->chaddr));
372dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
373dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
374dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 1;
375dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
376dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
377dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define STATE_SELECTING  1
378dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define STATE_REQUESTING 2
379dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
380dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define TIMEOUT_INITIAL   4000
381dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define TIMEOUT_MAX      32000
382dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
383dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint dhcp_init_ifc(const char *ifname)
384dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
385dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dhcp_msg discover_msg;
386dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dhcp_msg request_msg;
387dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dhcp_msg reply;
388dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dhcp_msg *msg;
389dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dhcp_info info;
390dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int s, r, size;
391dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int valid_reply;
392dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t xid;
393dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned char hwaddr[6];
394dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct pollfd pfd;
395dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned int state;
396dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned int timeout;
397dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int if_index;
398dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
399dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    xid = (uint32_t) get_msecs();
400dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
401dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (ifc_get_hwaddr(ifname, hwaddr)) {
402dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return fatal("cannot obtain interface address");
403dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
404dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (ifc_get_ifindex(ifname, &if_index)) {
405dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return fatal("cannot obtain interface index");
406dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
407dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
408dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    s = open_raw_socket(ifname, hwaddr, if_index);
409dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
410dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    timeout = TIMEOUT_INITIAL;
411dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    state = STATE_SELECTING;
412dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    info.type = 0;
413dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    goto transmit;
414dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
415dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    for (;;) {
416dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        pfd.fd = s;
417dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        pfd.events = POLLIN;
418dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        pfd.revents = 0;
419dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        r = poll(&pfd, 1, timeout);
420dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
421dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (r == 0) {
422dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE
423dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            printerr("TIMEOUT\n");
424dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
425dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (timeout >= TIMEOUT_MAX) {
426dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                printerr("timed out\n");
427dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                if ( info.type == DHCPOFFER ) {
428dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    printerr("no acknowledgement from DHCP server\nconfiguring %s with offered parameters\n", ifname);
4298c85a00db6da092ec3766facd49132fa4fc319a1Szymon Jakubczak                    return dhcp_configure(ifname, &info);
430dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                }
431dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                errno = ETIME;
432dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                close(s);
433dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                return -1;
434dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
435dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            timeout = timeout * 2;
436dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
437dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        transmit:
438dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            size = 0;
439dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            msg = NULL;
440dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            switch(state) {
441dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            case STATE_SELECTING:
442dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                msg = &discover_msg;
443dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                size = init_dhcp_discover_msg(msg, hwaddr, xid);
444dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                break;
445dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            case STATE_REQUESTING:
446dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                msg = &request_msg;
447dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                size = init_dhcp_request_msg(msg, hwaddr, xid, info.ipaddr, info.serveraddr);
448dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                break;
449dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            default:
450dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                r = 0;
451dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
452dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (size != 0) {
453dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                r = send_message(s, if_index, msg, size);
454dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                if (r < 0) {
455dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    printerr("error sending dhcp msg: %s\n", strerror(errno));
456dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                }
457dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
458dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            continue;
459dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
460dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
461dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (r < 0) {
462dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if ((errno == EAGAIN) || (errno == EINTR)) {
463dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                continue;
464dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
465dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            return fatal("poll failed");
466dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
467dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
468dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        errno = 0;
469dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        r = receive_packet(s, &reply);
470dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (r < 0) {
471dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (errno != 0) {
4728d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block                ALOGD("receive_packet failed (%d): %s", r, strerror(errno));
473dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                if (errno == ENETDOWN || errno == ENXIO) {
474dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    return -1;
475dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                }
476dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
477dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            continue;
478dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
479dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
480dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE > 1
481dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        dump_dhcp_msg(&reply, r);
482dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
483dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        decode_dhcp_msg(&reply, r, &info);
484dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
485dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (state == STATE_SELECTING) {
486dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            valid_reply = is_valid_reply(&discover_msg, &reply, r);
487dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        } else {
488dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            valid_reply = is_valid_reply(&request_msg, &reply, r);
489dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
490dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (!valid_reply) {
491dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            printerr("invalid reply\n");
492dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            continue;
493dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
494dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
495dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (verbose) dump_dhcp_info(&info);
496dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
497dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        switch(state) {
498dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case STATE_SELECTING:
499dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (info.type == DHCPOFFER) {
500dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                state = STATE_REQUESTING;
501dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                timeout = TIMEOUT_INITIAL;
502dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                xid++;
503dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                goto transmit;
504dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
505dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
506dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case STATE_REQUESTING:
507dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (info.type == DHCPACK) {
508dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                printerr("configuring %s\n", ifname);
509dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                close(s);
5108c85a00db6da092ec3766facd49132fa4fc319a1Szymon Jakubczak                return dhcp_configure(ifname, &info);
511dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            } else if (info.type == DHCPNAK) {
512dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                printerr("configuration request denied\n");
513dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                close(s);
514dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                return -1;
515dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            } else {
516dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                printerr("ignoring %s message in state %d\n",
517dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                         dhcp_type_to_name(info.type), state);
518dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
519dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
520dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
521dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
522dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    close(s);
523dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 0;
524dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
525dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
526dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint do_dhcp(char *iname)
527dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
528dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (ifc_set_addr(iname, 0)) {
529dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        printerr("failed to set ip addr for %s to 0.0.0.0: %s\n", iname, strerror(errno));
530dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
531dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
532dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
533dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (ifc_up(iname)) {
534dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        printerr("failed to bring up interface %s: %s\n", iname, strerror(errno));
535dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
536dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
537dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
538dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return dhcp_init_ifc(iname);
539dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
540