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