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:
2006ee3ecc03a7cf9118e6a0b2577f15c76244bc408Chris Dearman            if (optlen >= 4) {
2016ee3ecc03a7cf9118e6a0b2577f15c76244bc408Chris Dearman                in_addr_t mask;
2026ee3ecc03a7cf9118e6a0b2577f15c76244bc408Chris Dearman                memcpy(&mask, x, 4);
2036ee3ecc03a7cf9118e6a0b2577f15c76244bc408Chris Dearman                info->prefixLength = ipv4NetmaskToPrefixLength(mask);
2046ee3ecc03a7cf9118e6a0b2577f15c76244bc408Chris Dearman            }
205dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
206dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case OPT_GATEWAY:
207dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (optlen >= 4) memcpy(&info->gateway, x, 4);
208dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
209dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case OPT_DNS:
210dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (optlen >= 4) memcpy(&info->dns1, x + 0, 4);
211dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (optlen >= 8) memcpy(&info->dns2, x + 4, 4);
212dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
213dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case OPT_LEASE_TIME:
214dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (optlen >= 4) {
215dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                memcpy(&info->lease, x, 4);
216dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                info->lease = ntohl(info->lease);
217dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
218dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
219dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case OPT_SERVER_ID:
220dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (optlen >= 4) memcpy(&info->serveraddr, x, 4);
221dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
222dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case OPT_MESSAGE_TYPE:
223dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            info->type = *x;
224dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
225dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        default:
226dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
227dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
228dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        x += optlen;
229dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        len -= optlen;
230dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
231dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
232dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    info->ipaddr = msg->yiaddr;
233dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
234dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 0;
235dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
236dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
237dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE
238dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
239dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void hex2str(char *buf, const unsigned char *array, int len)
240dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
241dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int i;
242dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char *cp = buf;
243dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
244dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    for (i = 0; i < len; i++) {
245dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        cp += sprintf(cp, " %02x ", array[i]);
246dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
247dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
248dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
249dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid dump_dhcp_msg(dhcp_msg *msg, int len)
250dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
251dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned char *x;
252dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned int n,c;
253dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int optsz;
254dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    const char *name;
255dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char buf[2048];
256dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
2578d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("===== DHCP message:");
258dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (len < DHCP_MSG_FIXED_SIZE) {
2598d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("Invalid length %d, should be %d", len, DHCP_MSG_FIXED_SIZE);
260dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return;
261dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
262dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
263dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    len -= DHCP_MSG_FIXED_SIZE;
264dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
265dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (msg->op == OP_BOOTREQUEST)
266dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        name = "BOOTREQUEST";
267dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    else if (msg->op == OP_BOOTREPLY)
268dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        name = "BOOTREPLY";
269dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    else
270dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        name = "????";
2718d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("op = %s (%d), htype = %d, hlen = %d, hops = %d",
272dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project           name, msg->op, msg->htype, msg->hlen, msg->hops);
2738d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("xid = 0x%08x secs = %d, flags = 0x%04x optlen = %d",
274dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project           ntohl(msg->xid), ntohs(msg->secs), ntohs(msg->flags), len);
2758d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("ciaddr = %s", ipaddr(msg->ciaddr));
2768d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("yiaddr = %s", ipaddr(msg->yiaddr));
2778d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("siaddr = %s", ipaddr(msg->siaddr));
2788d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("giaddr = %s", ipaddr(msg->giaddr));
279dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
280dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    c = msg->hlen > 16 ? 16 : msg->hlen;
281dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    hex2str(buf, msg->chaddr, c);
2828d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("chaddr = {%s}", buf);
283dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
284dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    for (n = 0; n < 64; n++) {
285dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if ((msg->sname[n] < ' ') || (msg->sname[n] > 127)) {
286dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (msg->sname[n] == 0) break;
287dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            msg->sname[n] = '.';
288dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
289dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
290dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msg->sname[63] = 0;
291dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
292dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    for (n = 0; n < 128; n++) {
293dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if ((msg->file[n] < ' ') || (msg->file[n] > 127)) {
294dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (msg->file[n] == 0) break;
295dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            msg->file[n] = '.';
296dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
297dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
298dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msg->file[127] = 0;
299dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
3008d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("sname = '%s'", msg->sname);
3018d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("file = '%s'", msg->file);
302dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
303dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (len < 4) return;
304dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    len -= 4;
305dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    x = msg->options + 4;
306dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
307dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    while (len > 2) {
308dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (*x == 0) {
309dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            x++;
310dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            len--;
311dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            continue;
312dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
313dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (*x == OPT_END) {
314dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
315dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
316dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        len -= 2;
317dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        optsz = x[1];
318dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (optsz > len) break;
319dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (x[0] == OPT_DOMAIN_NAME || x[0] == OPT_MESSAGE) {
320dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if ((unsigned int)optsz < sizeof(buf) - 1) {
321dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                n = optsz;
322dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            } else {
323dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                n = sizeof(buf) - 1;
324dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
325dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            memcpy(buf, &x[2], n);
326dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            buf[n] = '\0';
327dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        } else {
328dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            hex2str(buf, &x[2], optsz);
329dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
330dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (x[0] == OPT_MESSAGE_TYPE)
331dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            name = dhcp_type_to_name(x[2]);
332dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        else
333dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            name = NULL;
3348d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("op %d len %d {%s} %s", x[0], optsz, buf, name == NULL ? "" : name);
335dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        len -= optsz;
336dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        x = x + optsz + 2;
337dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
338dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
339dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
340dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
341dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
342dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic int send_message(int sock, int if_index, dhcp_msg  *msg, int size)
343dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
344dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE > 1
345dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dump_dhcp_msg(msg, size);
346dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
347dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return send_packet(sock, if_index, msg, size, INADDR_ANY, INADDR_BROADCAST,
348dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                       PORT_BOOTP_CLIENT, PORT_BOOTP_SERVER);
349dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
350dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
351dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic int is_valid_reply(dhcp_msg *msg, dhcp_msg *reply, int sz)
352dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
353dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (sz < DHCP_MSG_FIXED_SIZE) {
3548d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        if (verbose) ALOGD("netcfg: Wrong size %d != %d\n", sz, DHCP_MSG_FIXED_SIZE);
355dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
356dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
357dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (reply->op != OP_BOOTREPLY) {
3588d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        if (verbose) ALOGD("netcfg: Wrong Op %d != %d\n", reply->op, OP_BOOTREPLY);
359dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
360dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
361dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (reply->xid != msg->xid) {
3628d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        if (verbose) ALOGD("netcfg: Wrong Xid 0x%x != 0x%x\n", ntohl(reply->xid),
363dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                          ntohl(msg->xid));
364dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
365dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
366dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (reply->htype != msg->htype) {
3678d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        if (verbose) ALOGD("netcfg: Wrong Htype %d != %d\n", reply->htype, msg->htype);
368dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
369dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
370dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (reply->hlen != msg->hlen) {
3718d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        if (verbose) ALOGD("netcfg: Wrong Hlen %d != %d\n", reply->hlen, msg->hlen);
372dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
373dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
374dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (memcmp(msg->chaddr, reply->chaddr, msg->hlen)) {
3758d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        if (verbose) ALOGD("netcfg: Wrong chaddr %x != %x\n", *(reply->chaddr),*(msg->chaddr));
376dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
377dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
378dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 1;
379dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
380dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
381dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define STATE_SELECTING  1
382dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define STATE_REQUESTING 2
383dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
384dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define TIMEOUT_INITIAL   4000
385dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define TIMEOUT_MAX      32000
386dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
387dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint dhcp_init_ifc(const char *ifname)
388dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
389dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dhcp_msg discover_msg;
390dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dhcp_msg request_msg;
391dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dhcp_msg reply;
392dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dhcp_msg *msg;
393dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    dhcp_info info;
394dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int s, r, size;
395dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int valid_reply;
396dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uint32_t xid;
397dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned char hwaddr[6];
398dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct pollfd pfd;
399dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned int state;
400dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unsigned int timeout;
401dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int if_index;
402dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
403dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    xid = (uint32_t) get_msecs();
404dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
405dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (ifc_get_hwaddr(ifname, hwaddr)) {
406dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return fatal("cannot obtain interface address");
407dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
408dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (ifc_get_ifindex(ifname, &if_index)) {
409dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return fatal("cannot obtain interface index");
410dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
411dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
412dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    s = open_raw_socket(ifname, hwaddr, if_index);
413dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
414dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    timeout = TIMEOUT_INITIAL;
415dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    state = STATE_SELECTING;
416dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    info.type = 0;
417dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    goto transmit;
418dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
419dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    for (;;) {
420dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        pfd.fd = s;
421dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        pfd.events = POLLIN;
422dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        pfd.revents = 0;
423dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        r = poll(&pfd, 1, timeout);
424dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
425dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (r == 0) {
426dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE
427dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            printerr("TIMEOUT\n");
428dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
429dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (timeout >= TIMEOUT_MAX) {
430dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                printerr("timed out\n");
431dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                if ( info.type == DHCPOFFER ) {
432dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    printerr("no acknowledgement from DHCP server\nconfiguring %s with offered parameters\n", ifname);
4338c85a00db6da092ec3766facd49132fa4fc319a1Szymon Jakubczak                    return dhcp_configure(ifname, &info);
434dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                }
435dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                errno = ETIME;
436dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                close(s);
437dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                return -1;
438dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
439dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            timeout = timeout * 2;
440dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
441dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        transmit:
442dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            size = 0;
443dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            msg = NULL;
444dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            switch(state) {
445dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            case STATE_SELECTING:
446dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                msg = &discover_msg;
447dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                size = init_dhcp_discover_msg(msg, hwaddr, xid);
448dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                break;
449dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            case STATE_REQUESTING:
450dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                msg = &request_msg;
451dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                size = init_dhcp_request_msg(msg, hwaddr, xid, info.ipaddr, info.serveraddr);
452dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                break;
453dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            default:
454dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                r = 0;
455dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
456dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (size != 0) {
457dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                r = send_message(s, if_index, msg, size);
458dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                if (r < 0) {
459dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    printerr("error sending dhcp msg: %s\n", strerror(errno));
460dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                }
461dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
462dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            continue;
463dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
464dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
465dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (r < 0) {
466dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if ((errno == EAGAIN) || (errno == EINTR)) {
467dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                continue;
468dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
469dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            return fatal("poll failed");
470dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
471dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
472dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        errno = 0;
473dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        r = receive_packet(s, &reply);
474dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (r < 0) {
475dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (errno != 0) {
4768d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block                ALOGD("receive_packet failed (%d): %s", r, strerror(errno));
477dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                if (errno == ENETDOWN || errno == ENXIO) {
478dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    return -1;
479dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                }
480dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
481dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            continue;
482dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
483dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
484dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#if VERBOSE > 1
485dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        dump_dhcp_msg(&reply, r);
486dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#endif
487dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        decode_dhcp_msg(&reply, r, &info);
488dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
489dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (state == STATE_SELECTING) {
490dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            valid_reply = is_valid_reply(&discover_msg, &reply, r);
491dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        } else {
492dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            valid_reply = is_valid_reply(&request_msg, &reply, r);
493dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
494dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (!valid_reply) {
495dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            printerr("invalid reply\n");
496dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            continue;
497dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
498dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
499dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (verbose) dump_dhcp_info(&info);
500dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
501dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        switch(state) {
502dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case STATE_SELECTING:
503dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (info.type == DHCPOFFER) {
504dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                state = STATE_REQUESTING;
505dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                timeout = TIMEOUT_INITIAL;
506dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                xid++;
507dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                goto transmit;
508dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
509dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
510dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case STATE_REQUESTING:
511dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (info.type == DHCPACK) {
512dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                printerr("configuring %s\n", ifname);
513dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                close(s);
5148c85a00db6da092ec3766facd49132fa4fc319a1Szymon Jakubczak                return dhcp_configure(ifname, &info);
515dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            } else if (info.type == DHCPNAK) {
516dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                printerr("configuration request denied\n");
517dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                close(s);
518dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                return -1;
519dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            } else {
520dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                printerr("ignoring %s message in state %d\n",
521dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                         dhcp_type_to_name(info.type), state);
522dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
523dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
524dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
525dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
526dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    close(s);
527dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 0;
528dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
529dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
530dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint do_dhcp(char *iname)
531dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{
532dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (ifc_set_addr(iname, 0)) {
533dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        printerr("failed to set ip addr for %s to 0.0.0.0: %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    if (ifc_up(iname)) {
538dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        printerr("failed to bring up interface %s: %s\n", iname, strerror(errno));
539dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
540dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
541dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
542dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return dhcp_init_ifc(iname);
543dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
544