dhcpclient.c revision 8c85a00db6da092ec3766facd49132fa4fc319a1
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
734f55adc323a32cf2c7fb851fab86c9372e3b2cbfNick Kralevich    LOGD("%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
96dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projecttypedef struct dhcp_info dhcp_info;
97dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
98dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstruct dhcp_info {
99dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t type;
100dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
101dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t ipaddr;
102dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t gateway;
103dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t netmask;
104dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
105dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t dns1;
106dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t dns2;
107dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
108dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t serveraddr;
109dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t lease;
110dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project};
111dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
112dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectdhcp_info last_good_info;
113dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
114dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *mask,
115dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                   uint32_t *dns1, uint32_t *dns2, uint32_t *server,
116dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                   uint32_t *lease)
117dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
118dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    *ipaddr = last_good_info.ipaddr;
119dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    *gateway = last_good_info.gateway;
120dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    *mask = last_good_info.netmask;
121dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    *dns1 = last_good_info.dns1;
122dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    *dns2 = last_good_info.dns2;
123dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    *server = last_good_info.serveraddr;
124dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    *lease = last_good_info.lease;
125dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
126dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1278c85a00db6da092ec3766facd49132fa4fc319a1Szymon Jakubczakstatic int dhcp_configure(const char *ifname, dhcp_info *info)
128dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
129dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    last_good_info = *info;
1308c85a00db6da092ec3766facd49132fa4fc319a1Szymon Jakubczak    return ifc_configure(ifname, info->ipaddr, info->netmask, info->gateway,
1318c85a00db6da092ec3766facd49132fa4fc319a1Szymon Jakubczak                         info->dns1, info->dns2);
132dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
133dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
134dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic const char *dhcp_type_to_name(uint32_t type)
135dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
136dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    switch(type) {
137dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    case DHCPDISCOVER: return "discover";
138dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    case DHCPOFFER:    return "offer";
139dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    case DHCPREQUEST:  return "request";
140dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    case DHCPDECLINE:  return "decline";
141dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    case DHCPACK:      return "ack";
142dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    case DHCPNAK:      return "nak";
143dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    case DHCPRELEASE:  return "release";
144dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    case DHCPINFORM:   return "inform";
145dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    default:           return "???";
146dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
147dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
148dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
149dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid dump_dhcp_info(dhcp_info *info)
150dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
151dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char addr[20], gway[20], mask[20];
152dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    LOGD("--- dhcp %s (%d) ---",
153dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            dhcp_type_to_name(info->type), info->type);
154dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    strcpy(addr, ipaddr(info->ipaddr));
155dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    strcpy(gway, ipaddr(info->gateway));
156dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    strcpy(mask, ipaddr(info->netmask));
157dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    LOGD("ip %s gw %s mask %s", addr, gway, mask);
158dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (info->dns1) LOGD("dns1: %s", ipaddr(info->dns1));
159dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (info->dns2) LOGD("dns2: %s", ipaddr(info->dns2));
160dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    LOGD("server %s, lease %d seconds",
161dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            ipaddr(info->serveraddr), info->lease);
162dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
163dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
164dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
165dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint decode_dhcp_msg(dhcp_msg *msg, int len, dhcp_info *info)
166dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
167dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint8_t *x;
168dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned int opt;
169dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int optlen;
170dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
171dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    memset(info, 0, sizeof(dhcp_info));
172dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (len < (DHCP_MSG_FIXED_SIZE + 4)) return -1;
173dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
174dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    len -= (DHCP_MSG_FIXED_SIZE + 4);
175dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
176dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (msg->options[0] != OPT_COOKIE1) return -1;
177dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (msg->options[1] != OPT_COOKIE2) return -1;
178dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (msg->options[2] != OPT_COOKIE3) return -1;
179dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (msg->options[3] != OPT_COOKIE4) return -1;
180dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
181dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    x = msg->options + 4;
182dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
183dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    while (len > 2) {
184dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        opt = *x++;
185dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (opt == OPT_PAD) {
186dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            len--;
187dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            continue;
188dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
189dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (opt == OPT_END) {
190dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
191dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
192dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        optlen = *x++;
193dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        len -= 2;
194dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (optlen > len) {
195dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
196dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
197dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        switch(opt) {
198dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case OPT_SUBNET_MASK:
199dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (optlen >= 4) memcpy(&info->netmask, x, 4);
200dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
201dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case OPT_GATEWAY:
202dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (optlen >= 4) memcpy(&info->gateway, x, 4);
203dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
204dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case OPT_DNS:
205dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (optlen >= 4) memcpy(&info->dns1, x + 0, 4);
206dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (optlen >= 8) memcpy(&info->dns2, x + 4, 4);
207dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
208dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case OPT_LEASE_TIME:
209dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (optlen >= 4) {
210dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                memcpy(&info->lease, x, 4);
211dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                info->lease = ntohl(info->lease);
212dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
213dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
214dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case OPT_SERVER_ID:
215dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (optlen >= 4) memcpy(&info->serveraddr, x, 4);
216dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
217dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case OPT_MESSAGE_TYPE:
218dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            info->type = *x;
219dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
220dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        default:
221dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
222dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
223dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        x += optlen;
224dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        len -= optlen;
225dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
226dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
227dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    info->ipaddr = msg->yiaddr;
228dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
229dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 0;
230dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
231dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
232dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE
233dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
234dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void hex2str(char *buf, const unsigned char *array, int len)
235dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
236dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int i;
237dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char *cp = buf;
238dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
239dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    for (i = 0; i < len; i++) {
240dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        cp += sprintf(cp, " %02x ", array[i]);
241dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
242dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
243dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
244dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid dump_dhcp_msg(dhcp_msg *msg, int len)
245dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
246dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned char *x;
247dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned int n,c;
248dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int optsz;
249dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    const char *name;
250dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char buf[2048];
251dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
252dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    LOGD("===== DHCP message:");
253dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (len < DHCP_MSG_FIXED_SIZE) {
254dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOGD("Invalid length %d, should be %d", len, DHCP_MSG_FIXED_SIZE);
255dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return;
256dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
257dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
258dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    len -= DHCP_MSG_FIXED_SIZE;
259dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
260dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (msg->op == OP_BOOTREQUEST)
261dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        name = "BOOTREQUEST";
262dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    else if (msg->op == OP_BOOTREPLY)
263dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        name = "BOOTREPLY";
264dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    else
265dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        name = "????";
266dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    LOGD("op = %s (%d), htype = %d, hlen = %d, hops = %d",
267dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project           name, msg->op, msg->htype, msg->hlen, msg->hops);
268dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    LOGD("xid = 0x%08x secs = %d, flags = 0x%04x optlen = %d",
269dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project           ntohl(msg->xid), ntohs(msg->secs), ntohs(msg->flags), len);
270dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    LOGD("ciaddr = %s", ipaddr(msg->ciaddr));
271dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    LOGD("yiaddr = %s", ipaddr(msg->yiaddr));
272dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    LOGD("siaddr = %s", ipaddr(msg->siaddr));
273dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    LOGD("giaddr = %s", ipaddr(msg->giaddr));
274dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
275dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    c = msg->hlen > 16 ? 16 : msg->hlen;
276dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    hex2str(buf, msg->chaddr, c);
277dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    LOGD("chaddr = {%s}", buf);
278dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
279dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    for (n = 0; n < 64; n++) {
280dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if ((msg->sname[n] < ' ') || (msg->sname[n] > 127)) {
281dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (msg->sname[n] == 0) break;
282dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            msg->sname[n] = '.';
283dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
284dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
285dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msg->sname[63] = 0;
286dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
287dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    for (n = 0; n < 128; n++) {
288dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if ((msg->file[n] < ' ') || (msg->file[n] > 127)) {
289dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (msg->file[n] == 0) break;
290dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            msg->file[n] = '.';
291dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
292dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
293dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msg->file[127] = 0;
294dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
295dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    LOGD("sname = '%s'", msg->sname);
296dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    LOGD("file = '%s'", msg->file);
297dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
298dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (len < 4) return;
299dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    len -= 4;
300dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    x = msg->options + 4;
301dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
302dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    while (len > 2) {
303dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (*x == 0) {
304dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            x++;
305dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            len--;
306dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            continue;
307dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
308dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (*x == OPT_END) {
309dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
310dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
311dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        len -= 2;
312dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        optsz = x[1];
313dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (optsz > len) break;
314dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (x[0] == OPT_DOMAIN_NAME || x[0] == OPT_MESSAGE) {
315dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if ((unsigned int)optsz < sizeof(buf) - 1) {
316dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                n = optsz;
317dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            } else {
318dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                n = sizeof(buf) - 1;
319dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
320dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            memcpy(buf, &x[2], n);
321dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            buf[n] = '\0';
322dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        } else {
323dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            hex2str(buf, &x[2], optsz);
324dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
325dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (x[0] == OPT_MESSAGE_TYPE)
326dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            name = dhcp_type_to_name(x[2]);
327dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        else
328dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            name = NULL;
329dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOGD("op %d len %d {%s} %s", x[0], optsz, buf, name == NULL ? "" : name);
330dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        len -= optsz;
331dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        x = x + optsz + 2;
332dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
333dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
334dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
335dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
336dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
337dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic int send_message(int sock, int if_index, dhcp_msg  *msg, int size)
338dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
339dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE > 1
340dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dump_dhcp_msg(msg, size);
341dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
342dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return send_packet(sock, if_index, msg, size, INADDR_ANY, INADDR_BROADCAST,
343dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                       PORT_BOOTP_CLIENT, PORT_BOOTP_SERVER);
344dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
345dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
346dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic int is_valid_reply(dhcp_msg *msg, dhcp_msg *reply, int sz)
347dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
348dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (sz < DHCP_MSG_FIXED_SIZE) {
349dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (verbose) LOGD("netcfg: Wrong size %d != %d\n", sz, DHCP_MSG_FIXED_SIZE);
350dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
351dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
352dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (reply->op != OP_BOOTREPLY) {
353dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (verbose) LOGD("netcfg: Wrong Op %d != %d\n", reply->op, OP_BOOTREPLY);
354dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
355dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
356dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (reply->xid != msg->xid) {
357dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (verbose) LOGD("netcfg: Wrong Xid 0x%x != 0x%x\n", ntohl(reply->xid),
358dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                          ntohl(msg->xid));
359dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
360dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
361dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (reply->htype != msg->htype) {
362dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (verbose) LOGD("netcfg: Wrong Htype %d != %d\n", reply->htype, msg->htype);
363dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
364dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
365dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (reply->hlen != msg->hlen) {
366dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (verbose) LOGD("netcfg: Wrong Hlen %d != %d\n", reply->hlen, msg->hlen);
367dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
368dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
369dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (memcmp(msg->chaddr, reply->chaddr, msg->hlen)) {
370dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (verbose) LOGD("netcfg: Wrong chaddr %x != %x\n", *(reply->chaddr),*(msg->chaddr));
371dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
372dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
373dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 1;
374dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
375dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
376dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define STATE_SELECTING  1
377dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define STATE_REQUESTING 2
378dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
379dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define TIMEOUT_INITIAL   4000
380dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define TIMEOUT_MAX      32000
381dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
382dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint dhcp_init_ifc(const char *ifname)
383dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
384dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dhcp_msg discover_msg;
385dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dhcp_msg request_msg;
386dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dhcp_msg reply;
387dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dhcp_msg *msg;
388dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dhcp_info info;
389dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int s, r, size;
390dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int valid_reply;
391dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t xid;
392dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned char hwaddr[6];
393dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct pollfd pfd;
394dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned int state;
395dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned int timeout;
396dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int if_index;
397dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
398dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    xid = (uint32_t) get_msecs();
399dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
400dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (ifc_get_hwaddr(ifname, hwaddr)) {
401dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return fatal("cannot obtain interface address");
402dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
403dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (ifc_get_ifindex(ifname, &if_index)) {
404dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return fatal("cannot obtain interface index");
405dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
406dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
407dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    s = open_raw_socket(ifname, hwaddr, if_index);
408dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
409dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    timeout = TIMEOUT_INITIAL;
410dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    state = STATE_SELECTING;
411dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    info.type = 0;
412dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    goto transmit;
413dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
414dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    for (;;) {
415dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        pfd.fd = s;
416dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        pfd.events = POLLIN;
417dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        pfd.revents = 0;
418dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        r = poll(&pfd, 1, timeout);
419dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
420dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (r == 0) {
421dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE
422dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            printerr("TIMEOUT\n");
423dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
424dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (timeout >= TIMEOUT_MAX) {
425dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                printerr("timed out\n");
426dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                if ( info.type == DHCPOFFER ) {
427dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    printerr("no acknowledgement from DHCP server\nconfiguring %s with offered parameters\n", ifname);
4288c85a00db6da092ec3766facd49132fa4fc319a1Szymon Jakubczak                    return dhcp_configure(ifname, &info);
429dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                }
430dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                errno = ETIME;
431dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                close(s);
432dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                return -1;
433dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
434dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            timeout = timeout * 2;
435dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
436dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        transmit:
437dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            size = 0;
438dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            msg = NULL;
439dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            switch(state) {
440dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            case STATE_SELECTING:
441dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                msg = &discover_msg;
442dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                size = init_dhcp_discover_msg(msg, hwaddr, xid);
443dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                break;
444dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            case STATE_REQUESTING:
445dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                msg = &request_msg;
446dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                size = init_dhcp_request_msg(msg, hwaddr, xid, info.ipaddr, info.serveraddr);
447dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                break;
448dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            default:
449dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                r = 0;
450dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
451dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (size != 0) {
452dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                r = send_message(s, if_index, msg, size);
453dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                if (r < 0) {
454dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    printerr("error sending dhcp msg: %s\n", strerror(errno));
455dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                }
456dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
457dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            continue;
458dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
459dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
460dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (r < 0) {
461dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if ((errno == EAGAIN) || (errno == EINTR)) {
462dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                continue;
463dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
464dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            return fatal("poll failed");
465dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
466dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
467dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        errno = 0;
468dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        r = receive_packet(s, &reply);
469dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (r < 0) {
470dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (errno != 0) {
471dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                LOGD("receive_packet failed (%d): %s", r, strerror(errno));
472dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                if (errno == ENETDOWN || errno == ENXIO) {
473dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    return -1;
474dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                }
475dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
476dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            continue;
477dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
478dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
479dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE > 1
480dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        dump_dhcp_msg(&reply, r);
481dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
482dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        decode_dhcp_msg(&reply, r, &info);
483dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
484dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (state == STATE_SELECTING) {
485dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            valid_reply = is_valid_reply(&discover_msg, &reply, r);
486dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        } else {
487dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            valid_reply = is_valid_reply(&request_msg, &reply, r);
488dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
489dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (!valid_reply) {
490dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            printerr("invalid reply\n");
491dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            continue;
492dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
493dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
494dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (verbose) dump_dhcp_info(&info);
495dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
496dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        switch(state) {
497dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case STATE_SELECTING:
498dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (info.type == DHCPOFFER) {
499dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                state = STATE_REQUESTING;
500dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                timeout = TIMEOUT_INITIAL;
501dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                xid++;
502dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                goto transmit;
503dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
504dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
505dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case STATE_REQUESTING:
506dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (info.type == DHCPACK) {
507dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                printerr("configuring %s\n", ifname);
508dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                close(s);
5098c85a00db6da092ec3766facd49132fa4fc319a1Szymon Jakubczak                return dhcp_configure(ifname, &info);
510dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            } else if (info.type == DHCPNAK) {
511dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                printerr("configuration request denied\n");
512dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                close(s);
513dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                return -1;
514dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            } else {
515dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                printerr("ignoring %s message in state %d\n",
516dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                         dhcp_type_to_name(info.type), state);
517dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
518dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
519dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
520dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
521dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    close(s);
522dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 0;
523dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
524dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
525dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint do_dhcp(char *iname)
526dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
527dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (ifc_set_addr(iname, 0)) {
528dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        printerr("failed to set ip addr for %s to 0.0.0.0: %s\n", iname, strerror(errno));
529dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
530dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
531dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
532dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (ifc_up(iname)) {
533dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        printerr("failed to bring up interface %s: %s\n", iname, strerror(errno));
534dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
535dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
536dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
537dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return dhcp_init_ifc(iname);
538dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
539